diff options
1019 files changed, 18758 insertions, 10400 deletions
diff --git a/Android.mk b/Android.mk index 278e67f9649a..4376ed6e4704 100644 --- a/Android.mk +++ b/Android.mk @@ -131,7 +131,7 @@ LOCAL_SRC_FILES += \ core/java/android/content/pm/IPackageInstallObserver.aidl \ core/java/android/content/pm/IPackageInstallObserver2.aidl \ core/java/android/content/pm/IPackageInstaller.aidl \ - core/java/android/content/pm/IPackageInstallerObserver.aidl \ + core/java/android/content/pm/IPackageInstallerCallback.aidl \ core/java/android/content/pm/IPackageInstallerSession.aidl \ core/java/android/content/pm/IPackageManager.aidl \ core/java/android/content/pm/IPackageMoveObserver.aidl \ @@ -155,7 +155,7 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \ core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \ core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl \ - core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl \ + core/java/android/hardware/hdmi/IHdmiRecordListener.aidl \ core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl \ core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl \ core/java/android/hardware/input/IInputManager.aidl \ @@ -215,7 +215,6 @@ LOCAL_SRC_FILES += \ core/java/android/print/IWriteResultCallback.aidl \ core/java/android/printservice/IPrintService.aidl \ core/java/android/printservice/IPrintServiceClient.aidl \ - core/java/android/service/dreams/IDozeHardware.aidl \ core/java/android/service/dreams/IDreamManager.aidl \ core/java/android/service/dreams/IDreamService.aidl \ core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \ @@ -349,8 +348,8 @@ LOCAL_SRC_FILES += \ media/java/android/media/tv/ITvInputServiceCallback.aidl \ media/java/android/media/tv/ITvInputSession.aidl \ media/java/android/media/tv/ITvInputSessionCallback.aidl \ - telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl \ - telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl \ + telecomm/java/com/android/internal/telecomm/IVideoCallCallback.aidl \ + telecomm/java/com/android/internal/telecomm/IVideoCallProvider.aidl \ telecomm/java/com/android/internal/telecomm/IConnectionService.aidl \ telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl \ telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl \ diff --git a/CleanSpec.mk b/CleanSpec.mk index 3014e0f4285d..fff8a858069c 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -212,6 +212,8 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telecomm/java/com/android/internal/telecomm) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework.* $(PRODUCT_OUT)/system/framework2.*) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/docs/api-stubs-timestamp) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER diff --git a/api/current.txt b/api/current.txt index 5d9d337ad6e9..8302bbaa163c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -564,9 +564,9 @@ package android { field public static final int fastScrollTextColor = 16843609; // 0x1010359 field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336 field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339 - field public static final int fill = 16843807; // 0x101041f field public static final int fillAfter = 16843197; // 0x10101bd field public static final int fillBefore = 16843196; // 0x10101bc + field public static final int fillColor = 16843807; // 0x101041f field public static final int fillEnabled = 16843343; // 0x101024f field public static final int fillOpacity = 16843806; // 0x101041e field public static final int fillViewport = 16843130; // 0x101017a @@ -1161,7 +1161,7 @@ package android { field public static final int streamType = 16843273; // 0x1010209 field public static final int stretchColumns = 16843081; // 0x1010149 field public static final int stretchMode = 16843030; // 0x1010116 - field public static final int stroke = 16843809; // 0x1010421 + field public static final int strokeColor = 16843809; // 0x1010421 field public static final int strokeLineCap = 16843815; // 0x1010427 field public static final int strokeLineJoin = 16843816; // 0x1010428 field public static final int strokeOpacity = 16843810; // 0x1010422 @@ -1388,6 +1388,7 @@ package android { field public static final int windowAllowExitTransitionOverlap = 16843837; // 0x101043d field public static final int windowAnimationStyle = 16842926; // 0x10100ae field public static final int windowBackground = 16842836; // 0x1010054 + field public static final int windowClipToOutline = 16843953; // 0x10104b1 field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b field public static final int windowContentOverlay = 16842841; // 0x1010059 field public static final int windowContentTransitionManager = 16843795; // 0x1010413 @@ -3392,6 +3393,7 @@ package android.app { method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet); method protected void onDestroy(); method public void onDetachedFromWindow(); + method public void onEnterAnimationComplete(); method public boolean onGenericMotionEvent(android.view.MotionEvent); method public boolean onKeyDown(int, android.view.KeyEvent); method public boolean onKeyLongPress(int, android.view.KeyEvent); @@ -3599,6 +3601,7 @@ package android.app { method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; + field public int affiliatedTaskId; field public android.content.Intent baseIntent; field public java.lang.CharSequence description; field public int id; @@ -5414,6 +5417,7 @@ package android.app.admin { field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN"; field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "android.app.extra.defaultManagedProfileName"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.deviceAdminPackageChecksum"; + field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.deviceAdminPackageDownloadCookieHeader"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.deviceAdminPackageDownloadLocation"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName"; field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.ManagedProfileEmailAddress"; @@ -7593,6 +7597,7 @@ package android.content { field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER"; field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS"; field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED"; + field public static final java.lang.String ACTION_CONFIRM_DEVICE_CREDENTIAL = "android.intent.action.CONFIRM_DEVICE_CREDENTIAL"; field public static final java.lang.String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT"; field public static final java.lang.String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT"; field public static final java.lang.String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED"; @@ -7735,6 +7740,7 @@ package android.content { field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list"; field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list"; field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED"; + field public static final java.lang.String EXTRA_DETAILS = "android.intent.extra.DETAILS"; field public static final java.lang.String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE"; field public static final int EXTRA_DOCK_STATE_CAR = 2; // 0x2 field public static final int EXTRA_DOCK_STATE_DESK = 1; // 0x1 @@ -8453,32 +8459,31 @@ package android.content.pm { public class InstallSessionInfo implements android.os.Parcelable { method public int describeContents(); - method public android.graphics.Bitmap getIcon(); + method public android.graphics.Bitmap getAppIcon(); + method public java.lang.CharSequence getAppLabel(); + method public java.lang.String getAppPackageName(); method public java.lang.String getInstallerPackageName(); - method public java.lang.String getPackageName(); - method public int getProgress(); + method public float getProgress(); method public int getSessionId(); - method public java.lang.CharSequence getTitle(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } public class InstallSessionParams implements android.os.Parcelable { - ctor public InstallSessionParams(); + ctor public InstallSessionParams(int); method public int describeContents(); - method public void setDeltaSize(long); - method public void setIcon(android.graphics.Bitmap); + method public void setAppIcon(android.graphics.Bitmap); + method public void setAppLabel(java.lang.CharSequence); + method public void setAppPackageName(java.lang.String); method public void setInstallLocation(int); - method public void setModeFullInstall(); - method public void setModeInheritExisting(); method public void setOriginatingUri(android.net.Uri); - method public void setPackageName(java.lang.String); - method public void setProgressMax(int); method public void setReferrerUri(android.net.Uri); method public void setSignatures(android.content.pm.Signature[]); - method public void setTitle(java.lang.CharSequence); + method public void setSize(long); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; + field public static final int MODE_FULL_INSTALL = 1; // 0x1 + field public static final int MODE_INHERIT_EXISTING = 2; // 0x2 } public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { @@ -8531,6 +8536,7 @@ package android.content.pm { method public boolean isPackageEnabledForProfile(java.lang.String, android.os.UserHandle); method public void removeOnAppsChangedCallback(android.content.pm.LauncherApps.OnAppsChangedCallback); method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle); + method public void showAppDetailsForProfile(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle); method public void startActivityForProfile(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle); } @@ -8578,42 +8584,47 @@ package android.content.pm { } public class PackageInstaller { + method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback); + method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); method public int createSession(android.content.pm.InstallSessionParams) throws java.io.IOException; - method public java.util.List<android.content.pm.InstallSessionInfo> getActiveSessions(); + method public java.util.List<android.content.pm.InstallSessionInfo> getAllSessions(); + method public java.util.List<android.content.pm.InstallSessionInfo> getMySessions(); + method public android.content.pm.InstallSessionInfo getSessionInfo(int); method public android.content.pm.PackageInstaller.Session openSession(int); - method public void registerSessionObserver(android.content.pm.PackageInstaller.SessionObserver); - method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallResultCallback); - method public void unregisterSessionObserver(android.content.pm.PackageInstaller.SessionObserver); + method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback); + method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallCallback); } - public static abstract class PackageInstaller.CommitResultCallback { - ctor public PackageInstaller.CommitResultCallback(); - method public abstract void onFailure(java.lang.String); - method public void onFailureConflict(java.lang.String, java.lang.String); - method public void onFailureIncompatible(java.lang.String); - method public void onFailureInvalid(java.lang.String); - method public void onFailureStorage(java.lang.String); + public static abstract class PackageInstaller.CommitCallback { + ctor public PackageInstaller.CommitCallback(); + method public abstract void onFailure(int, java.lang.String, android.os.Bundle); method public abstract void onSuccess(); + field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; + field public static final int FAILURE_CONFLICT = 2; // 0x2 + field public static final int FAILURE_INCOMPATIBLE = 4; // 0x4 + field public static final int FAILURE_INVALID = 1; // 0x1 + field public static final int FAILURE_STORAGE = 3; // 0x3 + field public static final int FAILURE_UNKNOWN = 0; // 0x0 } public static class PackageInstaller.Session implements java.io.Closeable { + method public void abandon(); method public void close(); - method public void commit(android.content.pm.PackageInstaller.CommitResultCallback); - method public void destroy(); + method public void commit(android.content.pm.PackageInstaller.CommitCallback); method public void fsync(java.io.OutputStream) throws java.io.IOException; method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException; - method public void setProgress(int); + method public void setProgress(float); } - public static abstract class PackageInstaller.SessionObserver { - ctor public PackageInstaller.SessionObserver(); - method public abstract void onCreated(android.content.pm.InstallSessionInfo); - method public abstract void onFinalized(int, boolean); - method public abstract void onProgress(int, int); + public static abstract class PackageInstaller.SessionCallback { + ctor public PackageInstaller.SessionCallback(); + method public abstract void onCreated(int); + method public abstract void onFinished(int, boolean); + method public abstract void onProgressChanged(int, float); } - public static abstract class PackageInstaller.UninstallResultCallback { - ctor public PackageInstaller.UninstallResultCallback(); + public static abstract class PackageInstaller.UninstallCallback { + ctor public PackageInstaller.UninstallCallback(); method public abstract void onFailure(java.lang.String); method public abstract void onSuccess(); } @@ -8680,7 +8691,6 @@ package android.content.pm { method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); - method public abstract android.content.pm.PackageInstaller getInstaller(); method public abstract java.lang.String getInstallerPackageName(java.lang.String); method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String); @@ -8690,6 +8700,7 @@ package android.content.pm { method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int); method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract android.content.pm.PackageInstaller getPackageInstaller(); method public abstract java.lang.String[] getPackagesForUid(int); method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int); method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -12646,7 +12657,6 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_TIMESTAMP_CALIBRATION; field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_WHITE_LEVEL; field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_MAX_ANALOG_SENSITIVITY; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_NOISE_PROFILE; field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_ORIENTATION; field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_REFERENCE_ILLUMINANT1; field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_REFERENCE_ILLUMINANT2; @@ -13020,6 +13030,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CaptureResult.Key SENSOR_FRAME_DURATION; field public static final android.hardware.camera2.CaptureResult.Key SENSOR_GREEN_SPLIT; field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NEUTRAL_COLOR_POINT; + field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NOISE_PROFILE; field public static final android.hardware.camera2.CaptureResult.Key SENSOR_ROLLING_SHUTTER_SKEW; field public static final android.hardware.camera2.CaptureResult.Key SENSOR_SENSITIVITY; field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_DATA; @@ -14134,10 +14145,10 @@ package android.media { method public void loadSoundEffects(); method public void playSoundEffect(int); method public void playSoundEffect(int, float); - method public void registerMediaButtonEventReceiver(android.content.ComponentName); - method public void registerMediaButtonEventReceiver(android.app.PendingIntent); - method public void registerRemoteControlClient(android.media.RemoteControlClient); - method public boolean registerRemoteController(android.media.RemoteController); + method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName); + method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent); + method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient); + method public deprecated boolean registerRemoteController(android.media.RemoteController); method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int); method public deprecated void setBluetoothA2dpOn(boolean); method public void setBluetoothScoOn(boolean); @@ -14156,10 +14167,10 @@ package android.media { method public void startBluetoothSco(); method public void stopBluetoothSco(); method public void unloadSoundEffects(); - method public void unregisterMediaButtonEventReceiver(android.content.ComponentName); - method public void unregisterMediaButtonEventReceiver(android.app.PendingIntent); - method public void unregisterRemoteControlClient(android.media.RemoteControlClient); - method public void unregisterRemoteController(android.media.RemoteController); + method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName); + method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent); + method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient); + method public deprecated void unregisterRemoteController(android.media.RemoteController); field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY"; field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED"; field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED"; @@ -14363,6 +14374,11 @@ package android.media { field public static final int QUALITY_720P = 5; // 0x5 field public static final int QUALITY_CIF = 3; // 0x3 field public static final int QUALITY_HIGH = 1; // 0x1 + field public static final int QUALITY_HIGH_SPEED_1080P = 2004; // 0x7d4 + field public static final int QUALITY_HIGH_SPEED_480P = 2002; // 0x7d2 + field public static final int QUALITY_HIGH_SPEED_720P = 2003; // 0x7d3 + field public static final int QUALITY_HIGH_SPEED_HIGH = 2001; // 0x7d1 + field public static final int QUALITY_HIGH_SPEED_LOW = 2000; // 0x7d0 field public static final int QUALITY_LOW = 0; // 0x0 field public static final int QUALITY_QCIF = 2; // 0x2 field public static final int QUALITY_QVGA = 7; // 0x7 @@ -14991,6 +15007,7 @@ package android.media { field public static final java.lang.String KEY_AAC_SBR_MODE = "aac-sbr-mode"; field public static final java.lang.String KEY_BITRATE_MODE = "bitrate-mode"; field public static final java.lang.String KEY_BIT_RATE = "bitrate"; + field public static final java.lang.String KEY_CAPTURE_RATE = "capture-rate"; field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count"; field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask"; field public static final java.lang.String KEY_COLOR_FORMAT = "color-format"; @@ -16170,7 +16187,7 @@ package android.media.browse { method public android.net.Uri getRoot(); method public android.media.session.MediaSession.Token getSessionToken(); method public boolean isConnected(); - method public void loadThumbnail(android.net.Uri, int, int, android.media.browse.MediaBrowser.ThumbnailCallback); + method public void loadIcon(android.net.Uri, int, int, android.media.browse.MediaBrowser.IconCallback); method public void subscribe(android.net.Uri, android.media.browse.MediaBrowser.SubscriptionCallback); method public void unsubscribe(android.net.Uri); } @@ -16182,16 +16199,16 @@ package android.media.browse { method public void onConnectionSuspended(); } - public static abstract class MediaBrowser.SubscriptionCallback { - ctor public MediaBrowser.SubscriptionCallback(); - method public void onChildrenLoaded(android.net.Uri, java.util.List<android.media.browse.MediaBrowserItem>); + public static abstract class MediaBrowser.IconCallback { + ctor public MediaBrowser.IconCallback(); method public void onError(android.net.Uri); + method public void onIconLoaded(android.net.Uri, android.graphics.Bitmap); } - public static abstract class MediaBrowser.ThumbnailCallback { - ctor public MediaBrowser.ThumbnailCallback(); + public static abstract class MediaBrowser.SubscriptionCallback { + ctor public MediaBrowser.SubscriptionCallback(); + method public void onChildrenLoaded(android.net.Uri, java.util.List<android.media.browse.MediaBrowserItem>); method public void onError(android.net.Uri); - method public void onThumbnailLoaded(android.net.Uri, android.graphics.Bitmap); } public final class MediaBrowserItem implements android.os.Parcelable { @@ -16227,8 +16244,8 @@ package android.media.browse { method public void notifyChildrenChanged(android.net.Uri); method public android.os.IBinder onBind(android.content.Intent); method public abstract android.media.browse.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle); - method protected abstract void onLoadChildren(android.net.Uri, android.media.browse.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowserItem>>); - method protected abstract void onLoadThumbnail(android.net.Uri, int, int, android.media.browse.MediaBrowserService.Result<android.graphics.Bitmap>); + method public abstract void onLoadChildren(android.net.Uri, android.media.browse.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowserItem>>); + method public abstract void onLoadIcon(android.net.Uri, int, int, android.media.browse.MediaBrowserService.Result<android.graphics.Bitmap>); method public void setSessionToken(android.media.session.MediaSession.Token); field public static final java.lang.String SERVICE_ACTION = "android.media.browse.MediaBrowserService"; } @@ -16562,16 +16579,20 @@ package android.media.routing { package android.media.session { public final class MediaController { - ctor public MediaController(android.media.session.MediaSession.Token); + ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token); method public void addCallback(android.media.session.MediaController.Callback); method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler); method public void adjustVolume(int, int); method public android.media.routing.MediaRouter.Delegate createMediaRouterDelegate(); method public boolean dispatchMediaButtonEvent(android.view.KeyEvent); + method public long getFlags(); + method public android.app.PendingIntent getLaunchActivity(); method public android.media.MediaMetadata getMetadata(); + method public java.lang.String getPackageName(); method public android.media.session.PlaybackState getPlaybackState(); method public java.util.List<android.media.session.MediaSession.Track> getQueue(); method public int getRatingType(); + method public android.media.session.MediaSession.Token getSessionToken(); method public android.media.session.MediaController.TransportControls getTransportControls(); method public android.media.session.MediaController.VolumeInfo getVolumeInfo(); method public void removeCallback(android.media.session.MediaController.Callback); @@ -16621,6 +16642,7 @@ package android.media.session { method public void addCallback(android.media.session.MediaSession.Callback, android.os.Handler); method public void addTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback); method public void addTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback, android.os.Handler); + method public android.media.session.MediaController getController(); method public android.media.session.MediaSession.Token getSessionToken(); method public boolean isActive(); method public void release(); @@ -16630,7 +16652,8 @@ package android.media.session { method public void setActive(boolean); method public void setExtras(android.os.Bundle); method public void setFlags(int); - method public void setLaunchPendingIntent(android.app.PendingIntent); + method public void setLaunchActivity(android.app.PendingIntent); + method public void setMediaButtonReceiver(android.app.PendingIntent); method public void setMediaRouter(android.media.routing.MediaRouter); method public void setMetadata(android.media.MediaMetadata); method public void setPlaybackState(android.media.session.PlaybackState); @@ -16693,10 +16716,11 @@ package android.media.session { public final class MediaSessionManager { method public void addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, android.content.ComponentName); method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName); + method public void removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener); } public static abstract class MediaSessionManager.SessionListener { - ctor public MediaSessionManager.SessionListener(); + ctor public MediaSessionManager.SessionListener(android.content.Context); method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>); } @@ -16819,7 +16843,6 @@ package android.media.tv { public static final class TvContract.Channels implements android.media.tv.TvContract.BaseTvColumns { method public static final java.lang.String getVideoResolution(java.lang.String); - field public static final java.lang.String COLUMN_CONDITIONAL_ACCESS = "conditional_access"; field public static final java.lang.String COLUMN_DESCRIPTION = "description"; field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name"; field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number"; @@ -17000,12 +17023,12 @@ package android.media.tv { public abstract class TvInputService.Session implements android.view.KeyEvent.Callback { ctor public TvInputService.Session(); - method public void dispatchChannelRetuned(android.net.Uri); - method public void dispatchContentAllowed(); - method public void dispatchContentBlocked(android.media.tv.TvContentRating); - method public void dispatchTrackInfoChanged(java.util.List<android.media.tv.TvTrackInfo>); - method public void dispatchVideoAvailable(); - method public void dispatchVideoUnavailable(int); + method public void notifyChannelRetuned(android.net.Uri); + method public void notifyContentAllowed(); + method public void notifyContentBlocked(android.media.tv.TvContentRating); + method public void notifyTrackInfoChanged(java.util.List<android.media.tv.TvTrackInfo>); + method public void notifyVideoAvailable(); + method public void notifyVideoUnavailable(int); method public android.view.View onCreateOverlayView(); method public boolean onGenericMotionEvent(android.view.MotionEvent); method public boolean onKeyDown(int, android.view.KeyEvent); @@ -17013,7 +17036,6 @@ package android.media.tv { method public boolean onKeyMultiple(int, int, android.view.KeyEvent); method public boolean onKeyUp(int, android.view.KeyEvent); method public abstract void onRelease(); - method public void onRequestUnblockContent(android.media.tv.TvContentRating); method public boolean onSelectTrack(android.media.tv.TvTrackInfo); method public abstract void onSetCaptionEnabled(boolean); method public abstract void onSetStreamVolume(float); @@ -17022,6 +17044,7 @@ package android.media.tv { method public boolean onTouchEvent(android.view.MotionEvent); method public boolean onTrackballEvent(android.view.MotionEvent); method public abstract boolean onTune(android.net.Uri); + method public void onUnblockContent(android.media.tv.TvContentRating); method public boolean onUnselectTrack(android.media.tv.TvTrackInfo); method public void setOverlayViewEnabled(boolean); } @@ -17423,6 +17446,7 @@ package android.net { public class Network implements android.os.Parcelable { method public int describeContents(); method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException; + method public java.net.URL getBoundURL(java.net.URL) throws java.net.MalformedURLException; method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException; method public javax.net.SocketFactory getSocketFactory(); method public void writeToParcel(android.os.Parcel, int); @@ -22704,7 +22728,7 @@ package android.os { public class UserManager { method public android.os.Bundle getApplicationRestrictions(java.lang.String); method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle); - method public java.lang.String getBadgedLabelForUser(java.lang.String, android.os.UserHandle); + method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle); method public long getSerialNumberForUser(android.os.UserHandle); method public int getUserCount(); method public android.os.UserHandle getUserForSerialNumber(long); @@ -23963,6 +23987,7 @@ package android.provider { field public static final int PRESENTATION_PAYPHONE = 4; // 0x4 field public static final int PRESENTATION_RESTRICTED = 2; // 0x2 field public static final int PRESENTATION_UNKNOWN = 3; // 0x3 + field public static final java.lang.String TRANSCRIPTION = "transcription"; field public static final java.lang.String TYPE = "type"; field public static final int VOICEMAIL_TYPE = 4; // 0x4 field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri"; @@ -24340,6 +24365,7 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Event implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { + method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static int getTypeResource(java.lang.Integer); field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event"; field public static final java.lang.String START_DATE = "data1"; @@ -24838,7 +24864,7 @@ package android.provider { ctor public ContactsContract.PinnedPositions(); field public static final int DEMOTED = -1; // 0xffffffff field public static final java.lang.String UNDEMOTE_METHOD = "undemote"; - field public static final int UNPINNED = 2147483647; // 0x7fffffff + field public static final int UNPINNED = 0; // 0x0 } public static final deprecated class ContactsContract.Presence extends android.provider.ContactsContract.StatusUpdates { @@ -25524,11 +25550,13 @@ package android.provider { field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS"; field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS"; field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS"; + field public static final java.lang.String ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE"; field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS"; field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS"; field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS"; field public static final java.lang.String AUTHORITY = "settings"; field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types"; + field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled"; field public static final java.lang.String EXTRA_AUTHORITIES = "authorities"; field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id"; } @@ -28458,13 +28486,13 @@ package android.telecomm { method public void answer(int); method public void conference(); method public void disconnect(); - method public android.telecomm.RemoteCallVideoProvider getCallVideoProvider(); method public java.util.List<java.lang.String> getCannedTextResponses(); method public java.util.List<android.telecomm.Call> getChildren(); method public android.telecomm.Call.Details getDetails(); method public android.telecomm.Call getParent(); method public java.lang.String getRemainingPostDialSequence(); method public int getState(); + method public android.telecomm.InCallService.VideoCall getVideoCall(); method public void hold(); method public void phoneAccountClicked(); method public void phoneAccountSelected(android.telecomm.PhoneAccountHandle); @@ -28503,7 +28531,6 @@ package android.telecomm { public static abstract class Call.Listener { ctor public Call.Listener(); method public void onCallDestroyed(android.telecomm.Call); - method public void onCallVideoProviderChanged(android.telecomm.Call, android.telecomm.RemoteCallVideoProvider); method public void onCannedTextResponsesLoaded(android.telecomm.Call, java.util.List<java.lang.String>); method public void onChildrenChanged(android.telecomm.Call, java.util.List<android.telecomm.Call>); method public void onDetailsChanged(android.telecomm.Call, android.telecomm.Call.Details); @@ -28512,6 +28539,7 @@ package android.telecomm { method public void onPostDialWait(android.telecomm.Call, java.lang.String); method public void onStartActivity(android.telecomm.Call, android.app.PendingIntent); method public void onStateChanged(android.telecomm.Call, int); + method public void onVideoCallChanged(android.telecomm.Call, android.telecomm.InCallService.VideoCall); } public final class CallAudioState implements android.os.Parcelable { @@ -28575,53 +28603,25 @@ package android.telecomm { enum_constant public static final android.telecomm.CallState RINGING; } - public abstract class CallVideoClient { - ctor public CallVideoClient(); - method public abstract void onHandleCallSessionEvent(int); - method public abstract void onHandleCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities); - method public abstract void onReceiveSessionModifyRequest(android.telecomm.VideoCallProfile); - method public abstract void onReceiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile); - method public abstract void onUpdateCallDataUsage(int); - method public abstract void onUpdatePeerDimensions(int, int); - field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1 - field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2 - field public static final int SESSION_EVENT_TX_START = 3; // 0x3 - field public static final int SESSION_EVENT_TX_STOP = 4; // 0x4 - field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2 - field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3 - field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1 - } - - public abstract class CallVideoProvider { - ctor public CallVideoProvider(); - method public abstract void onRequestCallDataUsage(); - method public abstract void onRequestCameraCapabilities(); - method public abstract void onSendSessionModifyRequest(android.telecomm.VideoCallProfile); - method public abstract void onSendSessionModifyResponse(android.telecomm.VideoCallProfile); - method public abstract void onSetCallVideoClient(android.telecomm.RemoteCallVideoClient); - method public abstract void onSetCamera(java.lang.String); - method public abstract void onSetDeviceOrientation(int); - method public abstract void onSetDisplaySurface(android.view.Surface); - method public abstract void onSetPauseImage(java.lang.String); - method public abstract void onSetPreviewSurface(android.view.Surface); - method public abstract void onSetZoom(float); - } - public abstract class Connection { ctor public Connection(); method public final void destroy(); method public final boolean getAudioModeIsVoip(); method public final android.telecomm.CallAudioState getCallAudioState(); method public final int getCallCapabilities(); - method public final android.telecomm.CallVideoProvider getCallVideoProvider(); method public final java.lang.String getCallerDisplayName(); method public final int getCallerDisplayNamePresentation(); + method public static android.telecomm.Connection getCanceledConnection(); method public final java.util.List<android.telecomm.Connection> getChildConnections(); + method public static android.telecomm.Connection getFailedConnection(int, java.lang.String); + method public final int getFailureCode(); + method public final java.lang.String getFailureMessage(); method public final android.net.Uri getHandle(); method public final int getHandlePresentation(); method public final android.telecomm.Connection getParentConnection(); method public final int getState(); method public final android.telecomm.StatusHints getStatusHints(); + method public final android.telecomm.ConnectionService.VideoCallProvider getVideoCallProvider(); method public final int getVideoState(); method public final boolean isConferenceConnection(); method public final boolean isRequestingRingback(); @@ -28643,11 +28643,14 @@ package android.telecomm { method public final void setActive(); method public final void setAudioModeIsVoip(boolean); method public final void setCallCapabilities(int); - method public final void setCallVideoProvider(android.telecomm.CallVideoProvider); method public final void setCallerDisplayName(java.lang.String, int); + method public final void setCanceled(); method public final void setDialing(); method public final void setDisconnected(int, java.lang.String); + method public final void setFailed(int, java.lang.String); method public final void setHandle(android.net.Uri, int); + method public final void setInitialized(); + method public final void setInitializing(); method public final void setOnHold(); method public final void setParentConnection(android.telecomm.Connection); method public final void setPostDialWait(java.lang.String); @@ -28655,18 +28658,22 @@ package android.telecomm { method public final void setRinging(); method public final void setSignal(android.os.Bundle); method public final void setStatusHints(android.telecomm.StatusHints); + method public final void setVideoCallProvider(android.telecomm.ConnectionService.VideoCallProvider); method public final void setVideoState(int); method public final void startActivityFromInCall(android.app.PendingIntent); method public static java.lang.String stateToString(int); } public final class Connection.State { - field public static final int ACTIVE = 3; // 0x3 - field public static final int DIALING = 2; // 0x2 - field public static final int DISCONNECTED = 5; // 0x5 - field public static final int HOLDING = 4; // 0x4 - field public static final int NEW = 0; // 0x0 - field public static final int RINGING = 1; // 0x1 + field public static final int ACTIVE = 4; // 0x4 + field public static final int CANCELED = 8; // 0x8 + field public static final int DIALING = 3; // 0x3 + field public static final int DISCONNECTED = 6; // 0x6 + field public static final int FAILED = 7; // 0x7 + field public static final int HOLDING = 5; // 0x5 + field public static final int INITIALIZING = 0; // 0x0 + field public static final int NEW = 1; // 0x1 + field public static final int RINGING = 2; // 0x2 } public final class ConnectionRequest implements android.os.Parcelable { @@ -28684,17 +28691,16 @@ package android.telecomm { public abstract class ConnectionService extends android.app.Service { ctor public ConnectionService(); - method public final void createRemoteIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.RemoteConnection>); - method public final void createRemoteOutgoingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.RemoteConnection>); + method public final android.telecomm.RemoteConnection createRemoteIncomingConnection(android.telecomm.ConnectionRequest); + method public final android.telecomm.RemoteConnection createRemoteOutgoingConnection(android.telecomm.ConnectionRequest); method public final java.util.Collection<android.telecomm.Connection> getAllConnections(); - method public final void lookupRemoteAccounts(android.net.Uri, android.telecomm.SimpleResponse<android.net.Uri, java.util.List<android.telecomm.PhoneAccountHandle>>); method public final void maybeRespondToAccountLookup(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConnectionAdded(android.telecomm.Connection); method public void onConnectionRemoved(android.telecomm.Connection); method public void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>); - method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.Connection>); - method public void onCreateOutgoingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.Connection>); + method public android.telecomm.Connection onCreateIncomingConnection(android.telecomm.ConnectionRequest); + method public android.telecomm.Connection onCreateOutgoingConnection(android.telecomm.ConnectionRequest); field public static final java.lang.String SERVICE_INTERFACE = "android.telecomm.ConnectionService"; } @@ -28704,6 +28710,26 @@ package android.telecomm { method public abstract void onSuccess(android.telecomm.ConnectionRequest, CONNECTION); } + public static abstract class ConnectionService.VideoCallProvider { + ctor public ConnectionService.VideoCallProvider(); + method public void changeCallDataUsage(int); + method public void changeCameraCapabilities(android.telecomm.CallCameraCapabilities); + method public void changePeerDimensions(int, int); + method public void handleCallSessionEvent(int); + method public abstract void onRequestCallDataUsage(); + method public abstract void onRequestCameraCapabilities(); + method public abstract void onSendSessionModifyRequest(android.telecomm.VideoCallProfile); + method public abstract void onSendSessionModifyResponse(android.telecomm.VideoCallProfile); + method public abstract void onSetCamera(java.lang.String); + method public abstract void onSetDeviceOrientation(int); + method public abstract void onSetDisplaySurface(android.view.Surface); + method public abstract void onSetPauseImage(java.lang.String); + method public abstract void onSetPreviewSurface(android.view.Surface); + method public abstract void onSetZoom(float); + method public void receiveSessionModifyRequest(android.telecomm.VideoCallProfile); + method public void receiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile); + } + public class GatewayInfo implements android.os.Parcelable { method public int describeContents(); method public android.net.Uri getGatewayHandle(); @@ -28738,6 +28764,38 @@ package android.telecomm { method public void onPhoneDestroyed(android.telecomm.Phone); } + public static abstract class InCallService.VideoCall { + ctor public InCallService.VideoCall(); + method public abstract void requestCallDataUsage(); + method public abstract void requestCameraCapabilities(); + method public abstract void sendSessionModifyRequest(android.telecomm.VideoCallProfile); + method public abstract void sendSessionModifyResponse(android.telecomm.VideoCallProfile); + method public abstract void setCamera(java.lang.String); + method public abstract void setDeviceOrientation(int); + method public abstract void setDisplaySurface(android.view.Surface); + method public abstract void setPauseImage(java.lang.String); + method public abstract void setPreviewSurface(android.view.Surface); + method public abstract void setVideoCallListener(android.telecomm.InCallService.VideoCall.Listener); + method public abstract void setZoom(float); + field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1 + field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2 + field public static final int SESSION_EVENT_TX_START = 3; // 0x3 + field public static final int SESSION_EVENT_TX_STOP = 4; // 0x4 + field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2 + field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3 + field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1 + } + + public static abstract class InCallService.VideoCall.Listener { + ctor public InCallService.VideoCall.Listener(); + method public abstract void onCallDataUsageChanged(int); + method public abstract void onCallSessionEvent(int); + method public abstract void onCameraCapabilitiesChanged(android.telecomm.CallCameraCapabilities); + method public abstract void onPeerDimensionsChanged(int, int); + method public abstract void onSessionModifyRequestReceived(android.telecomm.VideoCallProfile); + method public abstract void onSessionModifyResponseReceived(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile); + } + public final class Phone { method public final void addListener(android.telecomm.Phone.Listener); method public final android.telecomm.CallAudioState getAudioState(); @@ -28782,29 +28840,6 @@ package android.telecomm { field public static final android.os.Parcelable.Creator CREATOR; } - public class RemoteCallVideoClient { - method public void handleCallSessionEvent(int); - method public void handleCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities); - method public void receiveSessionModifyRequest(android.telecomm.VideoCallProfile); - method public void receiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile); - method public void updateCallDataUsage(int); - method public void updatePeerDimensions(int, int); - } - - public class RemoteCallVideoProvider { - method public void requestCallDataUsage(); - method public void requestCameraCapabilities(); - method public void sendSessionModifyRequest(android.telecomm.VideoCallProfile); - method public void sendSessionModifyResponse(android.telecomm.VideoCallProfile); - method public void setCallVideoClient(android.telecomm.CallVideoClient); - method public void setCamera(java.lang.String); - method public void setDeviceOrientation(int); - method public void setDisplaySurface(android.view.Surface); - method public void setPauseImage(java.lang.String); - method public void setPreviewSurface(android.view.Surface); - method public void setZoom(float); - } - public final class RemoteConnection { method public void abort(); method public void addListener(android.telecomm.RemoteConnection.Listener); @@ -28816,6 +28851,8 @@ package android.telecomm { method public int getCallerDisplayNamePresentation(); method public int getDisconnectCause(); method public java.lang.String getDisconnectMessage(); + method public int getFailureCode(); + method public java.lang.String getFailureMessage(); method public android.net.Uri getHandle(); method public int getHandlePresentation(); method public int getState(); @@ -28832,19 +28869,20 @@ package android.telecomm { method public void unhold(); } - public static abstract interface RemoteConnection.Listener { - method public abstract void onAudioModeIsVoipChanged(android.telecomm.RemoteConnection, boolean); - method public abstract void onCallCapabilitiesChanged(android.telecomm.RemoteConnection, int); - method public abstract void onCallerDisplayNameChanged(android.telecomm.RemoteConnection, java.lang.String, int); - method public abstract void onDestroyed(android.telecomm.RemoteConnection); - method public abstract void onDisconnected(android.telecomm.RemoteConnection, int, java.lang.String); - method public abstract void onHandleChanged(android.telecomm.RemoteConnection, android.net.Uri, int); - method public abstract void onPostDialWait(android.telecomm.RemoteConnection, java.lang.String); - method public abstract void onRequestingRingback(android.telecomm.RemoteConnection, boolean); - method public abstract void onStartActivityFromInCall(android.telecomm.RemoteConnection, android.app.PendingIntent); - method public abstract void onStateChanged(android.telecomm.RemoteConnection, int); - method public abstract void onStatusHintsChanged(android.telecomm.RemoteConnection, android.telecomm.StatusHints); - method public abstract void onVideoStateChanged(android.telecomm.RemoteConnection, int); + public static abstract class RemoteConnection.Listener { + ctor public RemoteConnection.Listener(); + method public void onAudioModeIsVoipChanged(android.telecomm.RemoteConnection, boolean); + method public void onCallCapabilitiesChanged(android.telecomm.RemoteConnection, int); + method public void onCallerDisplayNameChanged(android.telecomm.RemoteConnection, java.lang.String, int); + method public void onDestroyed(android.telecomm.RemoteConnection); + method public void onDisconnected(android.telecomm.RemoteConnection, int, java.lang.String); + method public void onHandleChanged(android.telecomm.RemoteConnection, android.net.Uri, int); + method public void onPostDialWait(android.telecomm.RemoteConnection, java.lang.String); + method public void onRequestingRingback(android.telecomm.RemoteConnection, boolean); + method public void onStartActivityFromInCall(android.telecomm.RemoteConnection, android.app.PendingIntent); + method public void onStateChanged(android.telecomm.RemoteConnection, int); + method public void onStatusHintsChanged(android.telecomm.RemoteConnection, android.telecomm.StatusHints); + method public void onVideoStateChanged(android.telecomm.RemoteConnection, int); } public abstract interface Response { @@ -28891,6 +28929,20 @@ package android.telecomm { field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.intent.extra.START_CALL_WITH_VIDEO_STATE"; } + public class VideoCallImpl extends android.telecomm.InCallService.VideoCall { + method public void requestCallDataUsage(); + method public void requestCameraCapabilities(); + method public void sendSessionModifyRequest(android.telecomm.VideoCallProfile); + method public void sendSessionModifyResponse(android.telecomm.VideoCallProfile); + method public void setCamera(java.lang.String); + method public void setDeviceOrientation(int); + method public void setDisplaySurface(android.view.Surface); + method public void setPauseImage(java.lang.String); + method public void setPreviewSurface(android.view.Surface); + method public void setVideoCallListener(android.telecomm.InCallService.VideoCall.Listener); + method public void setZoom(float); + } + public class VideoCallProfile implements android.os.Parcelable { ctor public VideoCallProfile(int); ctor public VideoCallProfile(int, int); @@ -29091,7 +29143,7 @@ package android.telephony { field public static final int LIMIT_EXCEEDED = 15; // 0xf field public static final int LOCAL = 3; // 0x3 field public static final int LOST_SIGNAL = 14; // 0xe - field public static final int MAXIMUM_VALID_VALUE = 42; // 0x2a + field public static final int MAXIMUM_VALID_VALUE = 44; // 0x2c field public static final int MINIMUM_VALID_VALUE = 0; // 0x0 field public static final int MMI = 6; // 0x6 field public static final int NORMAL = 2; // 0x2 @@ -29099,6 +29151,8 @@ package android.telephony { field public static final int NOT_VALID = -1; // 0xffffffff field public static final int NO_PHONE_NUMBER_SUPPLIED = 38; // 0x26 field public static final int NUMBER_UNREACHABLE = 8; // 0x8 + field public static final int OUTGOING_CANCELED = 44; // 0x2c + field public static final int OUTGOING_FAILURE = 43; // 0x2b field public static final int OUT_OF_NETWORK = 11; // 0xb field public static final int OUT_OF_SERVICE = 18; // 0x12 field public static final int POWER_OFF = 17; // 0x11 @@ -30113,7 +30167,6 @@ package android.test.mock { method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); - method public android.content.pm.PackageInstaller getInstaller(); method public java.lang.String getInstallerPackageName(java.lang.String); method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String); @@ -30122,6 +30175,7 @@ package android.test.mock { method public java.lang.String getNameForUid(int); method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public android.content.pm.PackageInstaller getPackageInstaller(); method public java.lang.String[] getPackagesForUid(int); method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int); method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -36712,7 +36766,7 @@ package android.webkit { method public void removeSessionCookies(android.webkit.ValueCallback<java.lang.Boolean>); method public synchronized void setAcceptCookie(boolean); method public static void setAcceptFileSchemeCookies(boolean); - method public synchronized void setAcceptThirdPartyCookies(android.webkit.WebView, boolean); + method public void setAcceptThirdPartyCookies(android.webkit.WebView, boolean); method public void setCookie(java.lang.String, java.lang.String); method public void setCookie(java.lang.String, java.lang.String, android.webkit.ValueCallback<java.lang.Boolean>); } @@ -36858,23 +36912,31 @@ package android.webkit { method public void onRequestFocus(android.webkit.WebView); method public void onShowCustomView(android.view.View, android.webkit.WebChromeClient.CustomViewCallback); method public deprecated void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback); - method public boolean showFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams); + method public boolean onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams); } public static abstract interface WebChromeClient.CustomViewCallback { method public abstract void onCustomViewHidden(); } - public static class WebChromeClient.FileChooserParams { + public static abstract class WebChromeClient.FileChooserParams { ctor public WebChromeClient.FileChooserParams(); - field public static final int MODE_OPEN_FOLDER = 2; // 0x2 - field public static final int MODE_OPEN_MULTIPLE = 1; // 0x1 - field public static final int MODE_SAVE = 4; // 0x4 - field public java.lang.String acceptTypes; - field public boolean capture; - field public java.lang.String defaultFilename; - field public int mode; - field public java.lang.String title; + method public abstract java.lang.String[] getAcceptTypes(); + method public abstract java.lang.String getDefaultFilename(); + method public abstract int getMode(); + method public abstract java.lang.CharSequence getTitle(); + method public abstract android.webkit.WebChromeClient.UploadHelper getUploadHelper(); + method public abstract boolean isCaptureEnabled(); + field public static final int OPEN = 0; // 0x0 + field public static final int OPEN_FOLDER = 2; // 0x2 + field public static final int OPEN_MULTIPLE = 1; // 0x1 + field public static final int SAVE = 3; // 0x3 + } + + public static abstract class WebChromeClient.UploadHelper { + ctor public WebChromeClient.UploadHelper(); + method public abstract android.content.Intent buildIntent(); + method public abstract android.net.Uri[] parseResult(int, android.content.Intent); } public class WebHistoryItem implements java.lang.Cloneable { @@ -37126,6 +37188,7 @@ package android.webkit { method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String); method public void destroy(); method public void documentHasImages(android.os.Message); + method public static void enableSlowWholeDocumentDraw(); method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>); method public static java.lang.String findAddress(java.lang.String); method public deprecated int findAll(java.lang.String); @@ -39723,10 +39786,8 @@ package android.widget { method public void setLogo(android.graphics.drawable.Drawable); method public void setLogoDescription(int); method public void setLogoDescription(java.lang.CharSequence); - method public void setNavigationContentDescription(java.lang.CharSequence); method public void setNavigationContentDescription(int); - method public void setNavigationDescription(int); - method public void setNavigationDescription(java.lang.CharSequence); + method public void setNavigationContentDescription(java.lang.CharSequence); method public void setNavigationIcon(int); method public void setNavigationIcon(android.graphics.drawable.Drawable); method public void setNavigationOnClickListener(android.view.View.OnClickListener); diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 127b0fc6adf8..fa59e4b2df36 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -1465,7 +1465,7 @@ public class Am extends BaseCommand { System.out.println("Performing idle maintenance..."); Intent intent = new Intent( - "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE"); + "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE"); mAm.broadcastIntent(null, intent, null, null, 0, null, null, null, android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL); } diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java index c771f6506f57..7757b91c41c1 100644 --- a/cmds/media/src/com/android/commands/media/Media.java +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -19,16 +19,17 @@ package com.android.commands.media; import android.app.ActivityManager; import android.content.Context; +import android.content.pm.ParceledListSlice; import android.media.MediaMetadata; import android.media.session.ISessionController; +import android.media.session.ISessionControllerCallback; import android.media.session.ISessionManager; import android.media.session.MediaController; -import android.media.session.MediaSessionInfo; +import android.media.session.ParcelableVolumeInfo; import android.media.session.PlaybackState; import android.os.Bundle; import android.os.HandlerThread; import android.os.IBinder; -import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -62,14 +63,14 @@ public class Media extends BaseCommand { "usage: media [subcommand] [options]\n" + " media dispatch KEY\n" + " media list-sessions\n" + - " media monitor <sessionId>\n" + + " media monitor <tag>\n" + "\n" + "media dispatch: dispatch a media key to the system.\n" + " KEY may be: play, pause, play-pause, mute, headsethook,\n" + " stop, next, previous, rewind, record, fast-forword.\n" + "media list-sessions: print a list of the current sessions.\n" + "media monitor: monitor updates to the specified session.\n" + - " Use the sessionId from list-sessions.\n" + " Use the tag from list-sessions.\n" ); } @@ -114,13 +115,16 @@ public class Media extends BaseCommand { List<IBinder> sessions = mSessionService .getSessions(null, ActivityManager.getCurrentUser()); for (IBinder session : sessions) { - MediaController controller = new MediaController(ISessionController.Stub - .asInterface(session)); - if (controller != null && controller.getSessionInfo().getId().equals(id)) { - ControllerMonitor monitor = new ControllerMonitor(controller); - monitor.run(); - success = true; - break; + ISessionController controller = ISessionController.Stub.asInterface(session); + try { + if (controller != null && id.equals(controller.getTag())) { + ControllerMonitor monitor = new ControllerMonitor(controller); + monitor.run(); + success = true; + break; + } + } catch (RemoteException e) { + // ignore } } } catch (Exception e) { @@ -168,14 +172,14 @@ public class Media extends BaseCommand { KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); } - class ControllerMonitor extends MediaController.Callback { - private final MediaController mController; + class ControllerMonitor extends ISessionControllerCallback.Stub { + private final ISessionController mController; - public ControllerMonitor(MediaController controller) { + public ControllerMonitor(ISessionController controller) { mController = controller; } @Override - public void onSessionEvent(String event, Bundle extras) { + public void onEvent(String event, Bundle extras) { System.out.println("onSessionEvent event=" + event + ", extras=" + extras); } @@ -191,9 +195,33 @@ public class Media extends BaseCommand { System.out.println("onMetadataChanged " + mmString); } + @Override + public void onQueueChanged(ParceledListSlice queue) throws RemoteException { + System.out.println("onQueueChanged, size=" + queue.getList().size()); + } + + @Override + public void onQueueTitleChanged(CharSequence title) throws RemoteException { + System.out.println("onQueueTitleChange " + title); + } + + @Override + public void onExtrasChanged(Bundle extras) throws RemoteException { + System.out.println("onExtrasChanged " + extras); + } + + @Override + public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException { + System.out.println("onVolumeInfoChanged " + info); + } + void printUsageMessage() { - System.out.println("V2Monitoring session " + mController.getSessionInfo().getId() - + "... available commands:"); + try { + System.out.println("V2Monitoring session " + mController.getTag() + + "... available commands:"); + } catch (RemoteException e) { + System.out.println("Error trying to monitor session!"); + } System.out.println("(q)uit: finish monitoring"); } @@ -202,7 +230,11 @@ public class Media extends BaseCommand { HandlerThread cbThread = new HandlerThread("MediaCb") { @Override protected void onLooperPrepared() { - mController.addCallback(ControllerMonitor.this); + try { + mController.registerCallbackListener(ControllerMonitor.this); + } catch (RemoteException e) { + System.out.println("Error registering monitor callback"); + } } }; cbThread.start(); @@ -234,7 +266,7 @@ public class Media extends BaseCommand { } finally { cbThread.getLooper().quit(); try { - mController.removeCallback(this); + mController.unregisterCallbackListener(this); } catch (Exception e) { // ignoring } @@ -248,12 +280,15 @@ public class Media extends BaseCommand { List<IBinder> sessions = mSessionService .getSessions(null, ActivityManager.getCurrentUser()); for (IBinder session : sessions) { - MediaController controller = new MediaController(ISessionController.Stub - .asInterface(session)); + + ISessionController controller = ISessionController.Stub.asInterface(session); if (controller != null) { - MediaSessionInfo info = controller.getSessionInfo(); - System.out.println(" id=" + info.getId() + ", package=" - + info.getPackageName()); + try { + System.out.println(" tag=" + controller.getTag() + + ", package=" + controller.getPackageName()); + } catch (RemoteException e) { + // ignore + } } } } catch (Exception e) { diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index faf5622f38b6..bc168001927b 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -27,11 +27,12 @@ import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstaller; import android.content.pm.IPackageManager; +import android.content.pm.InstallSessionInfo; import android.content.pm.InstallSessionParams; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; -import android.content.pm.PackageInstaller.CommitResultCallback; +import android.content.pm.PackageInstaller.CommitCallback; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -157,8 +158,8 @@ public final class Pm { return; } - if ("install-destroy".equals(op)) { - runInstallDestroy(); + if ("install-abandon".equals(op) || "install-destroy".equals(op)) { + runInstallAbandon(); return; } @@ -252,6 +253,11 @@ public final class Pm { return; } + if ("force-dex-opt".equals(op)) { + runForceDexOpt(); + return; + } + try { if (args.length == 1) { if (args[0].equalsIgnoreCase("-l")) { @@ -770,7 +776,7 @@ public final class Pm { } } - class LocalCommitResultCallback extends CommitResultCallback { + class LocalCommitCallback extends CommitCallback { boolean finished; boolean success; String msg; @@ -790,7 +796,7 @@ public final class Pm { } @Override - public void onFailure(String msg) { + public void onFailure(int failureReason, String msg, Bundle extras) { setResult(false, msg); } } @@ -996,10 +1002,9 @@ public final class Pm { private void runInstallCreate() throws RemoteException { String installerPackageName = null; - final InstallSessionParams params = new InstallSessionParams(); + final InstallSessionParams params = new InstallSessionParams( + InstallSessionParams.MODE_FULL_INSTALL); params.installFlags = PackageManager.INSTALL_ALL_USERS; - params.setModeFullInstall(); - params.setProgressMax(-1); String opt; while ((opt = nextOption()) != null) { @@ -1021,11 +1026,9 @@ public final class Pm { } else if (opt.equals("-d")) { params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; } else if (opt.equals("-p")) { - params.setModeInheritExisting(); + params.mode = InstallSessionParams.MODE_INHERIT_EXISTING; } else if (opt.equals("-S")) { - final long deltaSize = Long.parseLong(nextOptionData()); - params.setDeltaSize(deltaSize); - params.setProgressMax((int) params.deltaSize); + params.setSize(Long.parseLong(nextOptionData())); } else if (opt.equals("--abi")) { params.abiOverride = checkAbiArgument(nextOptionData()); } else { @@ -1033,7 +1036,7 @@ public final class Pm { } } - final int sessionId = mInstaller.createSession(installerPackageName, params, + final int sessionId = mInstaller.createSession(params, installerPackageName, UserHandle.USER_OWNER); // NOTE: adb depends on parsing this string @@ -1080,7 +1083,12 @@ public final class Pm { final int n = Streams.copy(in, out); session.fsync(out); - session.addProgress(n); + + final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId); + if (info.sizeBytes > 0) { + final float fraction = ((float) n / (float) info.sizeBytes); + session.addProgress(fraction); + } System.out.println("Success: streamed " + n + " bytes"); } finally { @@ -1097,7 +1105,7 @@ public final class Pm { try { session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); - final LocalCommitResultCallback callback = new LocalCommitResultCallback(); + final LocalCommitCallback callback = new LocalCommitCallback(); session.commit(callback); synchronized (callback) { @@ -1118,13 +1126,13 @@ public final class Pm { } } - private void runInstallDestroy() throws RemoteException { + private void runInstallAbandon() throws RemoteException { final int sessionId = Integer.parseInt(nextArg()); PackageInstaller.Session session = null; try { session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); - session.destroy(); + session.abandon(); System.out.println("Success"); } finally { IoUtils.closeQuietly(session); @@ -1245,6 +1253,15 @@ public final class Pm { System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers()); } + public void runForceDexOpt() { + final String packageName = nextArg(); + try { + mPm.forceDexOpt(packageName); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + class PackageDeleteObserver extends IPackageDeleteObserver.Stub { boolean finished; boolean result; @@ -1743,7 +1760,7 @@ public final class Pm { System.err.println(" pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]"); System.err.println(" pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]"); System.err.println(" pm install-commit SESSION_ID"); - System.err.println(" pm install-destroy SESSION_ID"); + System.err.println(" pm install-abandon SESSION_ID"); System.err.println(" pm uninstall [-k] [--user USER_ID] PACKAGE"); System.err.println(" pm set-installer PACKAGE INSTALLER"); System.err.println(" pm clear [--user USER_ID] PACKAGE"); @@ -1813,7 +1830,7 @@ public final class Pm { System.err.println(" -S: size in bytes of package, required for stdin"); System.err.println(""); System.err.println("pm install-commit: perform install of fully staged session"); - System.err.println("pm install-destroy: destroy session"); + System.err.println("pm install-abandon: abandon session"); System.err.println(""); System.err.println("pm set-installer: set installer package name"); System.err.println(""); diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 19a91a67705f..13ceb4adfcdd 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -23,7 +23,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.os.SystemClock; import android.util.Log; import android.view.KeyEvent; import android.view.accessibility.AccessibilityEvent; @@ -659,16 +658,12 @@ public abstract class AccessibilityService extends Service { */ public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub implements HandlerCaller.Callback { - - static final int NO_ID = -1; - private static final int DO_SET_SET_CONNECTION = 1; private static final int DO_ON_INTERRUPT = 2; private static final int DO_ON_ACCESSIBILITY_EVENT = 3; private static final int DO_ON_GESTURE = 4; private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5; private static final int DO_ON_KEY_EVENT = 6; - private static final int DO_ON_WINDOWS_CHANGED = 7; private final HandlerCaller mCaller; @@ -715,12 +710,6 @@ public abstract class AccessibilityService extends Service { } @Override - public void onWindowsChanged(int[] windowIds) { - Message message = mCaller.obtainMessageO(DO_ON_WINDOWS_CHANGED, windowIds); - mCaller.sendMessage(message); - } - - @Override public void executeMessage(Message message) { switch (message.what) { case DO_ON_ACCESSIBILITY_EVENT: { @@ -791,31 +780,6 @@ public abstract class AccessibilityService extends Service { } } return; - case DO_ON_WINDOWS_CHANGED: { - final int[] windowIds = (int[]) message.obj; - - // Update the cached windows first. - // NOTE: The cache will hold on to the windows so do not recycle. - if (windowIds != null) { - AccessibilityInteractionClient.getInstance().removeWindows(windowIds); - } - - // Let the client know the windows changed. - AccessibilityEvent event = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_WINDOWS_CHANGED); - event.setEventTime(SystemClock.uptimeMillis()); - event.setSealed(true); - - mCallback.onAccessibilityEvent(event); - - // Make sure the event is recycled. - try { - event.recycle(); - } catch (IllegalStateException ise) { - /* ignore - best effort */ - } - } break; - default : Log.w(LOG_TAG, "Unknown message type " + message.what); } diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl index edd872712eb3..6ce0219b81f5 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl @@ -39,6 +39,4 @@ import android.view.KeyEvent; void clearAccessibilityCache(); void onKeyEvent(in KeyEvent event, int sequence); - - void onWindowsChanged(in int[] changedWindowIds); } diff --git a/core/java/android/accounts/CantAddAccountActivity.java b/core/java/android/accounts/CantAddAccountActivity.java index 4ac2bebc405c..f7f232e5c422 100644 --- a/core/java/android/accounts/CantAddAccountActivity.java +++ b/core/java/android/accounts/CantAddAccountActivity.java @@ -19,7 +19,6 @@ package android.accounts; import android.app.Activity; import android.os.Bundle; import android.view.View; -import android.widget.TextView; import com.android.internal.R; @@ -29,25 +28,11 @@ import com.android.internal.R; */ public class CantAddAccountActivity extends Activity { public static final String EXTRA_ERROR_CODE = "android.accounts.extra.ERROR_CODE"; - public static final int MISSING = -1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.app_not_authorized); - - int errorCode = getIntent().getIntExtra(EXTRA_ERROR_CODE, MISSING); - if (errorCode != MISSING) { - TextView errorText = (TextView) findViewById(R.id.description); - switch (errorCode) { - case AccountManager.ERROR_CODE_USER_RESTRICTED: - errorText.setText(R.string.app_no_restricted_accounts); - break; - default: - // TODO: Get better message. See: http://b/14642886 - errorText.setText(R.string.error_message_title); - } - } } public void onCancelButtonClicked(View view) { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index cac646d1c32a..394175a8d271 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -467,7 +467,7 @@ import java.util.HashMap; * * static final int PICK_CONTACT_REQUEST = 0; * - * protected boolean onKeyDown(int keyCode, KeyEvent event) { + * public boolean onKeyDown(int keyCode, KeyEvent event) { * if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { * // When the user center presses, let them pick a contact. * startActivityForResult( @@ -5501,6 +5501,14 @@ public class Activity extends ContextThemeWrapper } /** + * Activities cannot draw during the period that their windows are animating in. In order + * to know when it is safe to begin drawing they can override this method which will be + * called when the entering animation has completed. + */ + public void onEnterAnimationComplete() { + } + + /** * Adjust the current immersive mode setting. * * Note that changing this value will have no effect on the activity's diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index d43db78c3f85..fc2005508e28 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -697,7 +697,6 @@ public class ActivityManager { /** * Task affiliation for grouping with other tasks. - * @hide */ public int affiliatedTaskId; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 318a520594c5..311a8f55769d 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2231,6 +2231,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder token = data.readStrongBinder(); + notifyEnterAnimationComplete(token); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -5146,5 +5154,18 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + @Override + public void notifyEnterAnimationComplete(IBinder token) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(token); + mRemote.transact(NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION, data, reply, + IBinder.FLAG_ONEWAY); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 48954f4c4155..de5b9c4f62ad 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1163,6 +1163,10 @@ public final class ActivityThread { public void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean playing) { sendMessage(H.BACKGROUND_MEDIA_PLAYING_CHANGED, token, playing ? 1 : 0); } + + public void scheduleEnterAnimationComplete(IBinder token) { + sendMessage(H.ENTER_ANIMATION_COMPLETE, token); + } } private class H extends Handler { @@ -1215,6 +1219,7 @@ public final class ActivityThread { public static final int ON_NEW_ACTIVITY_OPTIONS = 146; public static final int STOP_MEDIA_PLAYING = 147; public static final int BACKGROUND_MEDIA_PLAYING_CHANGED = 148; + public static final int ENTER_ANIMATION_COMPLETE = 149; String codeToString(int code) { if (DEBUG_MESSAGES) { @@ -1267,6 +1272,7 @@ public final class ActivityThread { case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS"; case STOP_MEDIA_PLAYING: return "STOP_MEDIA_PLAYING"; case BACKGROUND_MEDIA_PLAYING_CHANGED: return "BACKGROUND_MEDIA_PLAYING_CHANGED"; + case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE"; } } return Integer.toString(code); @@ -1491,6 +1497,9 @@ public final class ActivityThread { case BACKGROUND_MEDIA_PLAYING_CHANGED: handleOnBackgroundMediaPlayingChanged((IBinder) msg.obj, msg.arg1 > 0); break; + case ENTER_ANIMATION_COMPLETE: + handleEnterAnimationComplete((IBinder) msg.obj); + break; } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what)); } @@ -2196,6 +2205,7 @@ public final class ActivityThread { cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); + r.intent.prepareToEnterProcess(); if (r.state != null) { r.state.setClassLoader(cl); } @@ -2420,6 +2430,7 @@ public final class ActivityThread { for (int i=0; i<N; i++) { Intent intent = intents.get(i); intent.setExtrasClassLoader(r.activity.getClassLoader()); + intent.prepareToEnterProcess(); r.activity.mFragments.noteStateNotSaved(); mInstrumentation.callActivityOnNewIntent(r.activity, intent); } @@ -2509,6 +2520,13 @@ public final class ActivityThread { installContentProviders(mInitialApplication, Lists.newArrayList(info)); } + private void handleEnterAnimationComplete(IBinder token) { + ActivityClientRecord r = mActivities.get(token); + if (r != null) { + r.activity.onEnterAnimationComplete(); + } + } + private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>(); /** @@ -2536,6 +2554,7 @@ public final class ActivityThread { try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); data.intent.setExtrasClassLoader(cl); + data.intent.prepareToEnterProcess(); data.setExtrasClassLoader(cl); receiver = (BroadcastReceiver)cl.loadClass(component).newInstance(); } catch (Exception e) { @@ -2737,6 +2756,7 @@ public final class ActivityThread { if (s != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); + data.intent.prepareToEnterProcess(); try { if (!data.rebind) { IBinder binder = s.onBind(data.intent); @@ -2765,6 +2785,7 @@ public final class ActivityThread { if (s != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); + data.intent.prepareToEnterProcess(); boolean doRebind = s.onUnbind(data.intent); try { if (doRebind) { @@ -2840,6 +2861,7 @@ public final class ActivityThread { try { if (data.args != null) { data.args.setExtrasClassLoader(s.getClassLoader()); + data.args.prepareToEnterProcess(); } int res; if (!data.taskRemoved) { @@ -3490,6 +3512,7 @@ public final class ActivityThread { try { if (ri.mData != null) { ri.mData.setExtrasClassLoader(r.activity.getClassLoader()); + ri.mData.prepareToEnterProcess(); } if (DEBUG_RESULTS) Slog.v(TAG, "Delivering result to activity " + r + " : " + ri); diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index ca9fabc03112..b3046b5aecff 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -549,7 +549,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { Bundle bundle = new Bundle(); RectF tempBounds = new RectF(); Matrix tempMatrix = new Matrix(); - for (int i = 0; i < mSharedElementNames.size(); i++) { + for (int i = 0; i < mSharedElements.size(); i++) { View sharedElement = mSharedElements.get(i); String name = mSharedElementNames.get(i); captureSharedElementState(sharedElement, name, bundle, tempMatrix, tempBounds); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 1cb0fd42608a..f18507e796b7 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -61,7 +61,10 @@ import android.os.UserManager; import android.util.ArrayMap; import android.util.Log; import android.view.Display; + +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; + import dalvik.system.VMRuntime; import java.lang.ref.WeakReference; @@ -74,13 +77,20 @@ final class ApplicationPackageManager extends PackageManager { private final static boolean DEBUG = false; private final static boolean DEBUG_ICONS = false; - UserManager mUserManager; + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private UserManager mUserManager; + @GuardedBy("mLock") + private PackageInstaller mInstaller; UserManager getUserManager() { - if (mUserManager == null) { - mUserManager = UserManager.get(mContext); + synchronized (mLock) { + if (mUserManager == null) { + mUserManager = UserManager.get(mContext); + } + return mUserManager; } - return mUserManager; } @Override @@ -1543,12 +1553,17 @@ final class ApplicationPackageManager extends PackageManager { } @Override - public PackageInstaller getInstaller() { - try { - return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getPackageName(), - mContext.getUserId()); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + public PackageInstaller getPackageInstaller() { + synchronized (mLock) { + if (mInstaller == null) { + try { + mInstaller = new PackageInstaller(this, mPM.getPackageInstaller(), + mContext.getPackageName(), mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + return mInstaller; } } @@ -1568,7 +1583,8 @@ final class ApplicationPackageManager extends PackageManager { public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId, int flags) { try { - mPM.addCrossProfileIntentFilter(filter, sourceUserId, targetUserId, flags); + mPM.addCrossProfileIntentFilter(filter, mContext.getOpPackageName(), + mContext.getUserId(), sourceUserId, targetUserId, flags); } catch (RemoteException e) { // Should never happen! } @@ -1592,7 +1608,8 @@ final class ApplicationPackageManager extends PackageManager { @Override public void clearCrossProfileIntentFilters(int sourceUserId) { try { - mPM.clearCrossProfileIntentFilters(sourceUserId); + mPM.clearCrossProfileIntentFilters(sourceUserId, mContext.getOpPackageName(), + mContext.getUserId()); } catch (RemoteException e) { // Should never happen! } @@ -1606,11 +1623,11 @@ final class ApplicationPackageManager extends PackageManager { return new BitmapDrawable(getUserManager().getUserIcon(itemInfo.showUserIcon)); } Drawable dr = getDrawable(itemInfo.packageName, itemInfo.icon, appInfo); - if (dr != null) { - dr = getUserManager().getBadgedDrawableForUser(dr, - new UserHandle(mContext.getUserId())); + if (dr == null) { + dr = getDefaultActivityIcon(); } - return dr; + return getUserManager().getBadgedDrawableForUser(dr, + new UserHandle(mContext.getUserId())); } private static class LegacyPackageInstallObserver extends PackageInstallObserver { diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 0b4510fe4c7e..e9d4bd9763e4 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -666,6 +666,15 @@ public abstract class ApplicationThreadNative extends Binder reply.writeNoException(); return true; } + + case ENTER_ANIMATION_COMPLETE_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + IBinder token = data.readStrongBinder(); + scheduleEnterAnimationComplete(token); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -1342,4 +1351,13 @@ class ApplicationThreadProxy implements IApplicationThread { mRemote.transact(BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } + + @Override + public void scheduleEnterAnimationComplete(IBinder token) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeStrongBinder(token); + mRemote.transact(ENTER_ANIMATION_COMPLETE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); + data.recycle(); + } } diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index a74fbdfcc031..f4eb5582159a 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -117,10 +117,16 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { setTransitionAlpha(mTransitioningViews, 1); setTransitionAlpha(mSharedElements, 1); mIsHidden = true; + if (getDecor() != null) { + getDecor().suppressLayout(false); + } clearState(); } private void sharedElementExitBack() { + if (getDecor() != null) { + getDecor().suppressLayout(true); + } if (!mSharedElements.isEmpty() && getSharedElementTransition() != null) { startTransition(new Runnable() { public void run() { @@ -136,17 +142,6 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { Transition transition = getSharedElementExitTransition(); final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames); - transition.addListener(new Transition.TransitionListenerAdapter() { - @Override - public void onTransitionEnd(Transition transition) { - transition.removeListener(this); - int count = mSharedElements.size(); - for (int i = 0; i < count; i++) { - View sharedElement = mSharedElements.get(i); - ((ViewGroup)sharedElement.getParent()).suppressLayout(true); - } - } - }); getDecor().getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override @@ -171,6 +166,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { public void startExit() { if (!mIsExitStarted) { mIsExitStarted = true; + if (getDecor() != null) { + getDecor().suppressLayout(true); + } startTransition(new Runnable() { @Override public void run() { @@ -183,6 +181,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { public void startExit(int resultCode, Intent data) { if (!mIsExitStarted) { mIsExitStarted = true; + if (getDecor() != null) { + getDecor().suppressLayout(true); + } mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -221,6 +222,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (transition != null) { TransitionManager.beginDelayedTransition(getDecor(), transition); mTransitioningViews.get(0).invalidate(); + } else { + transitionStarted(); } } @@ -307,6 +310,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (transition != null) { TransitionManager.beginDelayedTransition(getDecor(), transition); getDecor().invalidate(); + } else { + transitionStarted(); } } @@ -352,6 +357,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { mExitNotified = true; mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null); mResultReceiver = null; // done talking + if (getDecor() != null) { + getDecor().suppressLayout(false); + } finishIfNecessary(); } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 53c1408721e3..5347f03de885 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -448,6 +448,7 @@ public interface IActivityManager extends IInterface { public void mediaResourcesReleased(IBinder token) throws RemoteException; public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException; + public void notifyEnterAnimationComplete(IBinder token) throws RemoteException; /* * Private non-Binder interfaces @@ -758,4 +759,5 @@ public interface IActivityManager extends IInterface { int MEDIA_RESOURCES_RELEASED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+227; int NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+228; int START_ACTIVITY_FROM_RECENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 229; + int NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+230; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 18faf0e144c3..4a1fda4e8dde 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -147,6 +147,7 @@ public interface IApplicationThread extends IInterface { void updateTimePrefs(boolean is24Hour) throws RemoteException; void scheduleStopMediaPlaying(IBinder token) throws RemoteException; void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean enabled) throws RemoteException; + void scheduleEnterAnimationComplete(IBinder token) throws RemoteException; String descriptor = "android.app.IApplicationThread"; @@ -203,4 +204,5 @@ public interface IApplicationThread extends IInterface { int UPDATE_TIME_PREFS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+51; int STOP_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52; int BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53; + int ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54; } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index a193a345d88b..76cf29a3047e 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -18,6 +18,7 @@ package android.app.admin; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.app.Activity; import android.content.AbstractRestrictionsProvider; import android.content.ComponentName; @@ -272,6 +273,16 @@ public class DevicePolicyManager { = "android.app.extra.deviceAdminPackageDownloadLocation"; /** + * A String extra holding a http cookie header which should be used in the http request to the + * url specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. + * + * <p>Use in an Nfc record with {@link #PROVISIONING_NFC_MIME_TYPE} that starts device owner + * provisioning via an Nfc bump. + */ + public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER + = "android.app.extra.deviceAdminPackageDownloadCookieHeader"; + + /** * A String extra holding the SHA-1 checksum of the file at download location specified in * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. If this doesn't match * the file at the download location an error will be shown to the user and the user will be @@ -301,6 +312,7 @@ public class DevicePolicyManager { * <ul> * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</li> * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}</li> + * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li> * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}</li> * <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME} (convert to String), optional</li> * <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}, optional</li> @@ -2083,7 +2095,6 @@ public class DevicePolicyManager { /** * @hide - * @SystemApi * Sets the given component as an active admin and registers the package as the profile * owner for this user. The package must already be installed and there shouldn't be * an existing profile owner registered for this user. Also, this method must be called @@ -2097,6 +2108,7 @@ public class DevicePolicyManager { * @throws IllegalArgumentException if packageName is null, the package isn't installed, or * the user has already been set up. */ + @SystemApi public boolean setActiveProfileOwner(ComponentName admin, String ownerName) throws IllegalArgumentException { if (mService != null) { @@ -2390,8 +2402,9 @@ public class DevicePolicyManager { } /** - * Called by a profile owner to remove the cross-profile intent filters from the managed profile - * and from the parent. + * Called by a profile owner to remove the cross-profile intent filters that go from the + * managed profile to the parent, or from the parent to the managed profile. + * Only removes those that have been set by the profile owner. * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ public void clearCrossProfileIntentFilters(ComponentName admin) { diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java index 28108a001566..446c03eea98d 100644 --- a/core/java/android/app/backup/BackupTransport.java +++ b/core/java/android/app/backup/BackupTransport.java @@ -72,11 +72,11 @@ public class BackupTransport { * may offer a UI for allowing the user to supply login credentials for the * transport's off-device backend. * - * If the transport does not supply any user-facing configuration UI, it should - * return null from this method. + * <p>If the transport does not supply any user-facing configuration UI, it should + * return {@code null} from this method. * * @return An Intent that can be passed to Context.startActivity() in order to - * launch the transport's configuration UI. This method will return null + * launch the transport's configuration UI. This method will return {@code null} * if the transport does not offer any user-facing configuration UI. */ public Intent configurationIntent() { @@ -98,6 +98,43 @@ public class BackupTransport { } /** + * Ask the transport for an Intent that can be used to launch a more detailed + * secondary data management activity. For example, the configuration intent might + * be one for allowing the user to select which account they wish to associate + * their backups with, and the management intent might be one which presents a + * UI for managing the data on the backend. + * + * <p>In the Settings UI, the configuration intent will typically be invoked + * when the user taps on the preferences item labeled with the current + * destination string, and the management intent will be placed in an overflow + * menu labelled with the management label string. + * + * <p>If the transport does not supply any user-facing data management + * UI, then it should return {@code null} from this method. + * + * @return An intent that can be passed to Context.startActivity() in order to + * launch the transport's data-management UI. This method will return + * {@code null} if the transport does not offer any user-facing data + * management UI. + */ + public Intent dataManagementIntent() { + return null; + } + + /** + * On demand, supply a short string that can be shown to the user as the label + * on an overflow menu item used to invoked the data management UI. + * + * @return A string to be used as the label for the transport's data management + * affordance. If the transport supplies a data management intent, this + * method must not return {@code null}. + */ + public String dataManagementLabel() { + throw new UnsupportedOperationException( + "Transport dataManagementLabel() not implemented"); + } + + /** * Ask the transport where, on local device storage, to keep backup state blobs. * This is per-transport so that mock transports used for testing can coexist with * "live" backup services without interfering with the live bookkeeping. The @@ -446,6 +483,16 @@ public class BackupTransport { } @Override + public Intent dataManagementIntent() { + return BackupTransport.this.dataManagementIntent(); + } + + @Override + public String dataManagementLabel() { + return BackupTransport.this.dataManagementLabel(); + } + + @Override public String transportDirName() throws RemoteException { return BackupTransport.this.transportDirName(); } diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index d6345f3c3b4d..0d41be27bffa 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -29,11 +29,13 @@ public abstract class UsageStatsManagerInternal { * Reports an event to the UsageStatsManager. * * @param component The component for which this event ocurred. + * @param userId The user id to which the component belongs to. * @param timeStamp The time at which this event ocurred. * @param eventType The event that occured. Valid values can be found at * {@link android.app.usage.UsageStats.Event} */ - public abstract void reportEvent(ComponentName component, long timeStamp, int eventType); + public abstract void reportEvent(ComponentName component, int userId, + long timeStamp, int eventType); /** * Prepares the UsageStatsService for shutdown. diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 453d60c6cd6b..42b8dbf1a7f5 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -21,6 +21,8 @@ import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanFilter; +import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; @@ -354,27 +356,9 @@ public final class BluetoothAdapter { /** The profile is in disconnecting state */ public static final int STATE_DISCONNECTING = 3; - /** States for Bluetooth LE advertising */ - /** @hide */ - public static final int STATE_ADVERTISE_STARTING = 0; - /** @hide */ - public static final int STATE_ADVERTISE_STARTED = 1; - /** @hide */ - public static final int STATE_ADVERTISE_STOPPING = 2; - /** @hide */ - public static final int STATE_ADVERTISE_STOPPED = 3; - /** - * Force stopping advertising without callback in case the advertising app dies. - * @hide - */ - public static final int STATE_ADVERTISE_FORCE_STOPPING = 4; - /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; - /** @hide */ - public static final int ADVERTISE_CALLBACK_SUCCESS = 0; - private static final int ADDRESS_LENGTH = 17; private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; @@ -389,12 +373,14 @@ public final class BluetoothAdapter { */ private static BluetoothAdapter sAdapter; + private static BluetoothLeScanner sBluetoothLeScanner; + private static BluetoothLeAdvertiser sBluetoothLeAdvertiser; + private final IBluetoothManager mManagerService; private IBluetooth mService; - private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; - private final Handler mHandler; // Handler to post the advertise callback to run on main thread. private final Object mLock = new Object(); + private final Map<LeScanCallback, ScanCallback> mLeScanClients; /** * Get a handle to the default local Bluetooth adapter. @@ -429,8 +415,7 @@ public final class BluetoothAdapter { mService = managerService.registerAdapter(mManagerCallback); } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; - mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>(); - mHandler = new Handler(Looper.getMainLooper()); + mLeScanClients = new HashMap<LeScanCallback, ScanCallback>(); } /** @@ -469,19 +454,40 @@ public final class BluetoothAdapter { } /** - * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. + * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations, or + * null if Bluetooth LE Advertising is not support on this device. + * <p> + * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported + * on this device before calling this method. */ public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { - // TODO: Return null if this feature is not supported by hardware. - return new BluetoothLeAdvertiser(mManagerService); + if (getState() != STATE_ON) { + return null; + } + if (!isMultipleAdvertisementSupported()) { + return null; + } + synchronized(mLock) { + if (sBluetoothLeAdvertiser == null) { + sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); + } + } + return sBluetoothLeAdvertiser; } /** * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. */ public BluetoothLeScanner getBluetoothLeScanner() { - // TODO: Return null if BLE scan is not supported by hardware. - return new BluetoothLeScanner(mManagerService); + if (getState() != STATE_ON) { + return null; + } + synchronized(mLock) { + if (sBluetoothLeScanner == null) { + sBluetoothLeScanner = new BluetoothLeScanner(mManagerService); + } + } + return sBluetoothLeScanner; } /** @@ -1643,13 +1649,17 @@ public final class BluetoothAdapter { * instead. */ @Deprecated - public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { + public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); - if (callback == null) { if (DBG) Log.e(TAG, "startLeScan: null callback"); return false; } + BluetoothLeScanner scanner = getBluetoothLeScanner(); + if (scanner == null) { + if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); + return false; + } synchronized(mLeScanClients) { if (mLeScanClients.containsKey(callback)) { @@ -1664,13 +1674,50 @@ public final class BluetoothAdapter { return false; } - UUID uuid = UUID.randomUUID(); - GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids); - iGatt.registerClient(new ParcelUuid(uuid), wrapper); - if (wrapper.scanStarted()) { - mLeScanClients.put(callback, wrapper); - return true; + ScanCallback scanCallback = new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { + // Should not happen. + Log.e(TAG, "LE Scan has already started"); + return; + } + ScanRecord scanRecord = result.getScanRecord(); + if (scanRecord == null) { + return; + } + if (serviceUuids != null) { + List<ParcelUuid> uuids = new ArrayList<ParcelUuid>(); + for (UUID uuid : serviceUuids) { + uuids.add(new ParcelUuid(uuid)); + } + List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids(); + if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) { + if (DBG) Log.d(TAG, "uuids does not match"); + return; + } + } + callback.onLeScan(result.getDevice(), result.getRssi(), + scanRecord.getBytes()); + } + }; + ScanSettings settings = new ScanSettings.Builder() + .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); + + List<ScanFilter> filters = new ArrayList<ScanFilter>(); + if (serviceUuids != null && serviceUuids.length > 0) { + // Note scan filter does not support matching an UUID array so we put one + // UUID to hardware and match the whole array in callback. + ScanFilter filter = new ScanFilter.Builder().setServiceUuid( + new ParcelUuid(serviceUuids[0])).build(); + filters.add(filter); } + scanner.startScan(filters, settings, scanCallback); + + mLeScanClients.put(callback, scanCallback); + return true; + } catch (RemoteException e) { Log.e(TAG,"",e); } @@ -1690,264 +1737,17 @@ public final class BluetoothAdapter { @Deprecated public void stopLeScan(LeScanCallback callback) { if (DBG) Log.d(TAG, "stopLeScan()"); - GattCallbackWrapper wrapper; - synchronized(mLeScanClients) { - wrapper = mLeScanClients.remove(callback); - if (wrapper == null) return; - } - wrapper.stopLeScan(); - } - - /** - * Bluetooth GATT interface callbacks - */ - private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { - private static final int LE_CALLBACK_REG_TIMEOUT = 2000; - private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; - - private final LeScanCallback mLeScanCb; - - // mLeHandle 0: not registered - // -1: scan stopped - // >0: registered and scan started - private int mLeHandle; - private final UUID[] mScanFilter; - private WeakReference<BluetoothAdapter> mBluetoothAdapter; - - public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, - LeScanCallback leScanCb, UUID[] uuid) { - mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter); - mLeScanCb = leScanCb; - mScanFilter = uuid; - mLeHandle = 0; - } - - public boolean scanStarted() { - return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT); - } - - private boolean waitForRegisteration(int maxWaitCount) { - boolean started = false; - synchronized(this) { - if (mLeHandle == -1) return false; - int count = 0; - // wait for callback registration and LE scan to start - while (mLeHandle == 0 && count < maxWaitCount) { - try { - wait(LE_CALLBACK_REG_TIMEOUT); - } catch (InterruptedException e) { - Log.e(TAG, "Callback reg wait interrupted: " + e); - } - count++; - } - started = (mLeHandle > 0); - } - return started; - } - - public void stopLeScan() { - synchronized(this) { - if (mLeHandle <= 0) { - Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); - return; - } - BluetoothAdapter adapter = mBluetoothAdapter.get(); - if (adapter != null) { - try { - IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - iGatt.stopScan(mLeHandle, false); - iGatt.unregisterClient(mLeHandle); - } catch (RemoteException e) { - Log.e(TAG, "Failed to stop scan and unregister" + e); - } - } else { - Log.e(TAG, "stopLeScan, BluetoothAdapter is null"); - } - mLeHandle = -1; - notifyAll(); - } - } - - /** - * Application interface registered - app is ready to go - */ - public void onClientRegistered(int status, int clientIf) { - if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status + - " clientIf=" + clientIf); - synchronized(this) { - if (mLeHandle == -1) { - if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled"); - } - - if (status == BluetoothGatt.GATT_SUCCESS) { - mLeHandle = clientIf; - IBluetoothGatt iGatt = null; - try { - BluetoothAdapter adapter = mBluetoothAdapter.get(); - if (adapter != null) { - iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mScanFilter == null) { - iGatt.startScan(mLeHandle, false); - } else { - ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(mScanFilter[i]); - } - iGatt.startScanWithUuids(mLeHandle, false, uuids); - } - } else { - Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); - mLeHandle = -1; - } - } catch (RemoteException e) { - Log.e(TAG, "fail to start le scan: " + e); - mLeHandle = -1; - } - if (mLeHandle == -1) { - // registration succeeded but start scan or advertise failed - if (iGatt != null) { - try { - iGatt.unregisterClient(mLeHandle); - } catch (RemoteException e) { - Log.e(TAG, "fail to unregister callback: " + mLeHandle + - " error: " + e); - } - } - } - } else { - // registration failed - mLeHandle = -1; - } - notifyAll(); - } - } - - public void onClientConnectionState(int status, int clientIf, - boolean connected, String address) { - // no op + BluetoothLeScanner scanner = getBluetoothLeScanner(); + if (scanner == null) { + return; } - - /** - * Callback reporting an LE scan result. - * @hide - */ - public void onScanResult(String address, int rssi, byte[] advData) { - if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - - // Check null in case the scan has been stopped - synchronized(this) { - if (mLeHandle <= 0) return; - } - try { - BluetoothAdapter adapter = mBluetoothAdapter.get(); - if (adapter == null) { - Log.d(TAG, "onScanResult, BluetoothAdapter null"); - return; - } - mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); + synchronized (mLeScanClients) { + ScanCallback scanCallback = mLeScanClients.remove(callback); + if (scanCallback == null) { + if (DBG) Log.d(TAG, "scan not started yet"); + return; } - } - - public void onGetService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid) { - // no op - } - - public void onGetIncludedService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int inclSrvcType, int inclSrvcInstId, - ParcelUuid inclSrvcUuid) { - // no op - } - - public void onGetCharacteristic(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int charProps) { - // no op - } - - public void onGetDescriptor(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int descInstId, ParcelUuid descUuid) { - // no op - } - - public void onSearchComplete(String address, int status) { - // no op - } - - public void onCharacteristicRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, byte[] value) { - // no op - } - - public void onCharacteristicWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid) { - // no op - } - - public void onNotify(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - byte[] value) { - // no op - } - - public void onDescriptorRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int descInstId, ParcelUuid descrUuid, byte[] value) { - // no op - } - - public void onDescriptorWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int descInstId, ParcelUuid descrUuid) { - // no op - } - - public void onExecuteWrite(String address, int status) { - // no op - } - - public void onReadRemoteRssi(String address, int rssi, int status) { - // no op - } - - public void onAdvertiseStateChange(int advertiseState, int status) { - } - - @Override - public void onMultiAdvertiseCallback(int status) { - // no op - } - - @Override - public void onConfigureMTU(String address, int mtu, int status) { - // no op - } - - @Override - public void onConnectionCongested(String address, boolean congested) { - // no op - } - - @Override - public void onBatchScanResults(List<ScanResult> results) { - // no op - } - - @Override - public void onFoundOrLost(boolean onFound, String address,int rssi, - byte[] advData) { - // no op + scanner.stopScan(scanCallback); } } } diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 27f2011fcb59..1fe43ec77c87 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -491,6 +491,7 @@ public final class BluetoothGatt implements BluetoothProfile { mService.readDescriptor(mClientIf, address, srvcType, srvcInstId, srvcUuid, charInstId, charUuid, descrInstId, descrUuid, AUTHENTICATION_MITM); + return; } catch (RemoteException e) { Log.e(TAG,"",e); } @@ -544,6 +545,7 @@ public final class BluetoothGatt implements BluetoothProfile { srvcType, srvcInstId, srvcUuid, charInstId, charUuid, descrInstId, descrUuid, characteristic.getWriteType(), AUTHENTICATION_MITM, descriptor.getValue()); + return; } catch (RemoteException e) { Log.e(TAG,"",e); } diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index 533be13021d9..edf823e60d3a 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -33,10 +33,8 @@ import android.bluetooth.IBluetoothGattServerCallback; interface IBluetoothGatt { List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); - void startScan(in int appIf, in boolean isServer); - void startScanWithUuids(in int appIf, in boolean isServer, in ParcelUuid[] ids); - void startScanWithFilters(in int appIf, in boolean isServer, - in ScanSettings settings, in List<ScanFilter> filters); + void startScan(in int appIf, in boolean isServer, in ScanSettings settings, + in List<ScanFilter> filters); void stopScan(in int appIf, in boolean isServer); void flushPendingBatchResults(in int appIf, in boolean isServer); void startMultiAdvertising(in int appIf, diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java index 34fecfa60985..b137eeb0ce78 100644 --- a/core/java/android/bluetooth/le/AdvertiseData.java +++ b/core/java/android/bluetooth/le/AdvertiseData.java @@ -202,6 +202,7 @@ public final class AdvertiseData implements Parcelable { @Override public AdvertiseData createFromParcel(Parcel in) { Builder builder = new Builder(); + @SuppressWarnings("unchecked") List<ParcelUuid> uuids = in.readArrayList(ParcelUuid.class.getClassLoader()); if (uuids != null) { for (ParcelUuid uuid : uuids) { @@ -233,12 +234,6 @@ public final class AdvertiseData implements Parcelable { * Builder for {@link AdvertiseData}. */ public static final class Builder { - private static final int MAX_ADVERTISING_DATA_BYTES = 31; - // Each fields need one byte for field length and another byte for field type. - private static final int OVERHEAD_BYTES_PER_FIELD = 2; - // Flags field will be set by system. - private static final int FLAGS_FIELD_BYTES = 3; - @Nullable private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>(); private int mManufacturerId = -1; @@ -334,49 +329,5 @@ public final class AdvertiseData implements Parcelable { mServiceData, mManufacturerId, mManufacturerSpecificData, mIncludeTxPowerLevel, mIncludeDeviceName); } - - // Compute the size of the advertisement data. - private int totalBytes() { - int size = FLAGS_FIELD_BYTES; // flags field is always set. - if (mServiceUuids != null) { - int num16BitUuids = 0; - int num32BitUuids = 0; - int num128BitUuids = 0; - for (ParcelUuid uuid : mServiceUuids) { - if (BluetoothUuid.is16BitUuid(uuid)) { - ++num16BitUuids; - } else if (BluetoothUuid.is32BitUuid(uuid)) { - ++num32BitUuids; - } else { - ++num128BitUuids; - } - } - // 16 bit service uuids are grouped into one field when doing advertising. - if (num16BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD + - num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT; - } - // 32 bit service uuids are grouped into one field when doing advertising. - if (num32BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD + - num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT; - } - // 128 bit service uuids are grouped into one field when doing advertising. - if (num128BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD + - num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; - } - } - if (mServiceData != null) { - size += OVERHEAD_BYTES_PER_FIELD + mServiceData.length; - } - if (mManufacturerSpecificData != null) { - size += OVERHEAD_BYTES_PER_FIELD + mManufacturerSpecificData.length; - } - if (mIncludeTxPowerLevel) { - size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte. - } - return size; - } } } diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index fc53afe7a2a4..93d4349ba5b5 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -18,6 +18,7 @@ package android.bluetooth.le; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothUuid; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothGattCallback; import android.bluetooth.IBluetoothManager; @@ -49,6 +50,14 @@ public final class BluetoothLeAdvertiser { private static final String TAG = "BluetoothLeAdvertiser"; + private static final int MAX_ADVERTISING_DATA_BYTES = 31; + // Each fields need one byte for field length and another byte for field type. + private static final int OVERHEAD_BYTES_PER_FIELD = 2; + // Flags field will be set by system. + private static final int FLAGS_FIELD_BYTES = 3; + private static final int MANUFACTURER_SPECIFIC_DATA_LENGTH = 2; + private static final int SERVICE_DATA_UUID_LENGTH = 2; + private final IBluetoothManager mBluetoothManager; private final Handler mHandler; private BluetoothAdapter mBluetoothAdapter; @@ -101,6 +110,11 @@ public final class BluetoothLeAdvertiser { if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); } + if (totalBytes(advertiseData) > MAX_ADVERTISING_DATA_BYTES || + totalBytes(scanResponse) > MAX_ADVERTISING_DATA_BYTES) { + postCallbackFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); + return; + } if (mLeAdvertisers.containsKey(callback)) { postCallbackFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED); return; @@ -159,6 +173,62 @@ public final class BluetoothLeAdvertiser { } } + // Compute the size of the advertise data. + private int totalBytes(AdvertiseData data) { + if (data == null) { + return 0; + } + int size = FLAGS_FIELD_BYTES; // flags field is always set. + if (data.getServiceUuids() != null) { + int num16BitUuids = 0; + int num32BitUuids = 0; + int num128BitUuids = 0; + for (ParcelUuid uuid : data.getServiceUuids()) { + if (BluetoothUuid.is16BitUuid(uuid)) { + ++num16BitUuids; + } else if (BluetoothUuid.is32BitUuid(uuid)) { + ++num32BitUuids; + } else { + ++num128BitUuids; + } + } + // 16 bit service uuids are grouped into one field when doing advertising. + if (num16BitUuids != 0) { + size += OVERHEAD_BYTES_PER_FIELD + + num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT; + } + // 32 bit service uuids are grouped into one field when doing advertising. + if (num32BitUuids != 0) { + size += OVERHEAD_BYTES_PER_FIELD + + num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT; + } + // 128 bit service uuids are grouped into one field when doing advertising. + if (num128BitUuids != 0) { + size += OVERHEAD_BYTES_PER_FIELD + + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; + } + } + if (data.getServiceDataUuid() != null) { + size += OVERHEAD_BYTES_PER_FIELD + SERVICE_DATA_UUID_LENGTH + + byteLength(data.getServiceData()); + } + if (data.getManufacturerId() > 0) { + size += OVERHEAD_BYTES_PER_FIELD + MANUFACTURER_SPECIFIC_DATA_LENGTH + + byteLength(data.getManufacturerSpecificData()); + } + if (data.getIncludeTxPowerLevel()) { + size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte. + } + if (data.getIncludeDeviceName() && mBluetoothAdapter.getName() != null) { + size += OVERHEAD_BYTES_PER_FIELD + mBluetoothAdapter.getName().length(); + } + return size; + } + + private int byteLength(byte[] array) { + return array == null ? 0 : array.length; + } + /** * Bluetooth GATT interface callbacks for advertising. */ diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index 980f717a2f60..8e7d400898d6 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -151,6 +151,7 @@ public final class BluetoothLeScanner { synchronized (mLeScanClients) { BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback); if (wrapper == null) { + if (DBG) Log.d(TAG, "could not find callback wrapper"); return; } wrapper.stopLeScan(); @@ -266,7 +267,7 @@ public final class BluetoothLeScanner { if (status == BluetoothGatt.GATT_SUCCESS) { mClientIf = clientIf; try { - mBluetoothGatt.startScanWithFilters(mClientIf, false, mSettings, mFilters); + mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters); } catch (RemoteException e) { Log.e(TAG, "fail to start le scan: " + e); mClientIf = -1; diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index 0ae11b0cd99e..2ce18b0a83e2 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -107,7 +107,7 @@ public final class ScanFilter implements Parcelable { dest.writeParcelable(mServiceUuidMask, flags); } } - dest.writeInt(mServiceDataUuid == null? 0 : 1); + dest.writeInt(mServiceDataUuid == null ? 0 : 1); if (mServiceDataUuid != null) { dest.writeParcelable(mServiceDataUuid, flags); dest.writeInt(mServiceData == null ? 0 : mServiceData.length); @@ -235,6 +235,14 @@ public final class ScanFilter implements Parcelable { } /** + * @hide + */ + @Nullable + public ParcelUuid getServiceDataUuid() { + return mServiceDataUuid; + } + + /** * Returns the manufacturer id. -1 if the manufacturer filter is not set. */ public int getManufacturerId() { @@ -287,15 +295,21 @@ public final class ScanFilter implements Parcelable { } // Service data match - if (mServiceData != null && - !matchesPartialData(mServiceData, mServiceDataMask, scanRecord.getServiceData())) { - return false; + if (mServiceData != null) { + if (!Objects.equals(mServiceDataUuid, scanRecord.getServiceDataUuid()) || + !matchesPartialData(mServiceData, mServiceDataMask, + scanRecord.getServiceData())) { + return false; + } } // Manufacturer data match. - if (mManufacturerData != null && !matchesPartialData(mManufacturerData, - mManufacturerDataMask, scanRecord.getManufacturerSpecificData())) { - return false; + if (mManufacturerData != null) { + if (mManufacturerId != scanRecord.getManufacturerId() || + !matchesPartialData(mManufacturerData, + mManufacturerDataMask, scanRecord.getManufacturerSpecificData())) { + return false; + } } // All filters match. return true; @@ -353,7 +367,8 @@ public final class ScanFilter implements Parcelable { public String toString() { return "BluetoothLeScanFilter [mDeviceName=" + mDeviceName + ", mDeviceAddress=" + mDeviceAddress - + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask + ", mServiceData=" + + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask + + ", mServiceDataUuid=" + Objects.toString(mServiceDataUuid) + ", mServiceData=" + Arrays.toString(mServiceData) + ", mServiceDataMask=" + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId + ", mManufacturerData=" + Arrays.toString(mManufacturerData) @@ -363,7 +378,7 @@ public final class ScanFilter implements Parcelable { @Override public int hashCode() { return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId, mManufacturerData, - mManufacturerDataMask, mServiceData, mServiceDataMask, + mManufacturerDataMask, mServiceDataUuid, mServiceData, mServiceDataMask, mServiceUuid, mServiceUuidMask); } @@ -381,6 +396,7 @@ public final class ScanFilter implements Parcelable { mManufacturerId == other.mManufacturerId && Objects.deepEquals(mManufacturerData, other.mManufacturerData) && Objects.deepEquals(mManufacturerDataMask, other.mManufacturerDataMask) && + Objects.deepEquals(mServiceDataUuid, other.mServiceDataUuid) && Objects.deepEquals(mServiceData, other.mServiceData) && Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) && Objects.equals(mServiceUuid, other.mServiceUuid) && @@ -498,6 +514,7 @@ public final class ScanFilter implements Parcelable { "size mismatch for service data and service data mask"); } } + mServiceDataUuid = serviceDataUuid; mServiceData = serviceData; mServiceDataMask = serviceDataMask; return this; diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java index dd033080173a..e564c7d66ddd 100644 --- a/core/java/android/bluetooth/le/ScanRecord.java +++ b/core/java/android/bluetooth/le/ScanRecord.java @@ -225,20 +225,21 @@ public final class ScanRecord { txPowerLevel = scanRecord[currentPos]; break; case DATA_TYPE_SERVICE_DATA: - serviceData = extractBytes(scanRecord, currentPos, dataLength); - // The first two bytes of the service data are service data UUID. + // The first two bytes of the service data are service data UUID in little + // endian. The rest bytes are service data. int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT; byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos, serviceUuidLength); serviceDataUuid = BluetoothUuid.parseUuidFrom(serviceDataUuidBytes); + serviceData = extractBytes(scanRecord, currentPos + 2, dataLength - 2); break; case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA: - manufacturerSpecificData = extractBytes(scanRecord, currentPos, - dataLength); // The first two bytes of the manufacturer specific data are // manufacturer ids in little endian. - manufacturerId = ((manufacturerSpecificData[1] & 0xFF) << 8) + - (manufacturerSpecificData[0] & 0xFF); + manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) + + (scanRecord[currentPos] & 0xFF); + manufacturerSpecificData = extractBytes(scanRecord, currentPos + 2, + dataLength - 2); break; default: // Just ignore, we don't handle such data type. diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java index 9aee20094a8f..a0bdaffd8669 100644 --- a/core/java/android/bluetooth/le/ScanResult.java +++ b/core/java/android/bluetooth/le/ScanResult.java @@ -69,7 +69,7 @@ public final class ScanResult implements Parcelable { dest.writeInt(0); } if (mScanRecord != null) { - dest.writeInt(mScanRecord.getBytes().length); + dest.writeInt(1); dest.writeByteArray(mScanRecord.getBytes()); } else { dest.writeInt(0); @@ -145,7 +145,7 @@ public final class ScanResult implements Parcelable { @Override public String toString() { return "ScanResult{" + "mDevice=" + mDevice + ", mScanRecord=" - + mScanRecord.toString() + ", mRssi=" + mRssi + ", mTimestampNanos=" + + Objects.toString(mScanRecord) + ", mRssi=" + mRssi + ", mTimestampNanos=" + mTimestampNanos + '}'; } diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java index 2f86d09ec08c..b2ee6a82c94f 100644 --- a/core/java/android/bluetooth/le/ScanSettings.java +++ b/core/java/android/bluetooth/le/ScanSettings.java @@ -21,38 +21,37 @@ import android.os.Parcel; import android.os.Parcelable; /** - * Bluetooth LE scan settings are passed to {@link BluetoothLeScanner#startScan} - * to define the parameters for the scan. + * Bluetooth LE scan settings are passed to {@link BluetoothLeScanner#startScan} to define the + * parameters for the scan. */ public final class ScanSettings implements Parcelable { /** - * Perform Bluetooth LE scan in low power mode. - * This is the default scan mode as it consumes the least power. + * Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the + * least power. */ public static final int SCAN_MODE_LOW_POWER = 0; /** - * Perform Bluetooth LE scan in balanced power mode. - * Scan results are returned at a rate that provides a good trade-off between scan - * frequency and power consumption. + * Perform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that + * provides a good trade-off between scan frequency and power consumption. */ public static final int SCAN_MODE_BALANCED = 1; /** - * Scan using highest duty cycle. - * It's recommended to only use this mode when the application is running in the foreground. + * Scan using highest duty cycle. It's recommended to only use this mode when the application is + * running in the foreground. */ public static final int SCAN_MODE_LOW_LATENCY = 2; /** - * Trigger a callback for every Bluetooth advertisement found that matches the - * filter criteria. If no filter is active, all advertisement packets are reported. + * Trigger a callback for every Bluetooth advertisement found that matches the filter criteria. + * If no filter is active, all advertisement packets are reported. */ public static final int CALLBACK_TYPE_ALL_MATCHES = 1; /** - * A result callback is only triggered for the first advertisement packet received that - * matches the filter criteria. + * A result callback is only triggered for the first advertisement packet received that matches + * the filter criteria. */ public static final int CALLBACK_TYPE_FIRST_MATCH = 2; @@ -63,15 +62,17 @@ public final class ScanSettings implements Parcelable { public static final int CALLBACK_TYPE_MATCH_LOST = 4; /** - * Request full scan results which contain the device, rssi, advertising data, scan response - * as well as the scan timestamp. + * Request full scan results which contain the device, rssi, advertising data, scan response as + * well as the scan timestamp. */ public static final int SCAN_RESULT_TYPE_FULL = 0; /** * Request abbreviated scan results which contain the device, rssi and scan timestamp. - * <p><b>Note:</b> It is possible for an application to get more scan results than - * it asked for, if there are multiple apps using this type. + * <p> + * <b>Note:</b> It is possible for an application to get more scan results than it asked for, if + * there are multiple apps using this type. + * * @hide */ @SystemApi @@ -109,11 +110,11 @@ public final class ScanSettings implements Parcelable { } private ScanSettings(int scanMode, int callbackType, int scanResultType, - long reportDelaySeconds) { + long reportDelayMillis) { mScanMode = scanMode; mCallbackType = callbackType; mScanResultType = scanResultType; - mReportDelayMillis = reportDelaySeconds; + mReportDelayMillis = reportDelayMillis; } private ScanSettings(Parcel in) { @@ -184,15 +185,24 @@ public final class ScanSettings implements Parcelable { * @throws IllegalArgumentException If the {@code callbackType} is invalid. */ public Builder setCallbackType(int callbackType) { - if (callbackType < CALLBACK_TYPE_ALL_MATCHES - || callbackType > (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST) - || (callbackType & CALLBACK_TYPE_ALL_MATCHES) != CALLBACK_TYPE_ALL_MATCHES) { + + if (!isValidCallbackType(callbackType)) { throw new IllegalArgumentException("invalid callback type - " + callbackType); } mCallbackType = callbackType; return this; } + // Returns true if the callbackType is valid. + private boolean isValidCallbackType(int callbackType) { + if (callbackType == CALLBACK_TYPE_ALL_MATCHES || + callbackType == CALLBACK_TYPE_FIRST_MATCH || + callbackType == CALLBACK_TYPE_MATCH_LOST) { + return true; + } + return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST); + } + /** * Set scan result type for Bluetooth LE scan. * @@ -215,16 +225,15 @@ public final class ScanSettings implements Parcelable { /** * Set report delay timestamp for Bluetooth LE scan. - * @param reportDelayMillis Set to 0 to be notified of results immediately. - * Values > 0 causes the scan results to be queued - * up and delivered after the requested delay or when - * the internal buffers fill up. - * @throws IllegalArgumentException If {@code reportDelaySeconds} < 0. * + * @param reportDelayMillis Set to 0 to be notified of results immediately. Values > 0 + * causes the scan results to be queued up and delivered after the requested + * delay or when the internal buffers fill up. + * @throws IllegalArgumentException If {@code reportDelayMillis} < 0. */ public Builder setReportDelayMillis(long reportDelayMillis) { if (reportDelayMillis < 0) { - throw new IllegalArgumentException("reportDelaySeconds must be > 0"); + throw new IllegalArgumentException("reportDelayMillis must be > 0"); } mReportDelayMillis = reportDelayMillis; return this; diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 7a16ef8aefd7..d19604b27936 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -810,20 +810,16 @@ public class ClipData implements Parcelable { } } - /** - * Prepare this {@link ClipData} to leave an app process. - * - * @hide - */ - public void prepareToLeaveUser(int userId) { + /** @hide */ + public void fixUris(int contentUserHint) { final int size = mItems.size(); for (int i = 0; i < size; i++) { final Item item = mItems.get(i); if (item.mIntent != null) { - item.mIntent.prepareToLeaveUser(userId); + item.mIntent.fixUris(contentUserHint); } if (item.mUri != null) { - item.mUri = maybeAddUserId(item.mUri, userId); + item.mUri = maybeAddUserId(item.mUri, contentUserHint); } } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 287ea35e31e0..f224f40610e7 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -17,6 +17,7 @@ package android.content; import android.content.pm.ApplicationInfo; +import android.provider.MediaStore; import android.util.ArraySet; import org.xmlpull.v1.XmlPullParser; @@ -38,6 +39,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.StrictMode; +import android.os.UserHandle; import android.provider.DocumentsContract; import android.provider.DocumentsProvider; import android.provider.OpenableColumns; @@ -1413,6 +1415,21 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE"; /** + * Activity Action: Prompt the user to confirm credentials (pin, pattern or password) + * for the current user of the device. Launch this activity using + * {@link android.app.Activity#startActivityForResult(Intent, int)} and check if the + * result is {@link android.app.Activity#RESULT_OK} for a successful response to the + * challenge.<p/> + * This intent is handled by the system at a high priority and applications cannot intercept + * it.<p/> + * You can use {@link android.app.KeyguardManager#isKeyguardSecure()} to determine if the user will be + * prompted. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL = "android.intent.action.CONFIRM_DEVICE_CREDENTIAL"; + + + /** * Specify whether the package should be uninstalled for all users. * @hide because these should not be part of normal application flow. */ @@ -3160,11 +3177,17 @@ public class Intent implements Parcelable, Cloneable { /** * A CharSequence dialog title to provide to the user when used with a - * {@link #ACTION_CHOOSER}. + * {@link #ACTION_CHOOSER} or {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. */ public static final String EXTRA_TITLE = "android.intent.extra.TITLE"; /** + * A CharSequence description to provide to the user when used with + * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. + */ + public static final String EXTRA_DETAILS = "android.intent.extra.DETAILS"; + + /** * A Parcelable[] of {@link Intent} or * {@link android.content.pm.LabeledIntent} objects as set with * {@link #putExtra(String, Parcelable[])} of additional activities to place @@ -3937,6 +3960,7 @@ public class Intent implements Parcelable, Cloneable { private Rect mSourceBounds; private Intent mSelector; private ClipData mClipData; + private int mContentUserHint = UserHandle.USER_CURRENT; // --------------------------------------------------------------------- @@ -3956,6 +3980,7 @@ public class Intent implements Parcelable, Cloneable { this.mPackage = o.mPackage; this.mComponent = o.mComponent; this.mFlags = o.mFlags; + this.mContentUserHint = o.mContentUserHint; if (o.mCategories != null) { this.mCategories = new ArraySet<String>(o.mCategories); } @@ -4660,6 +4685,11 @@ public class Intent implements Parcelable, Cloneable { return mClipData; } + /** @hide */ + public int getContentUserHint() { + return mContentUserHint; + } + /** * Sets the ClassLoader that will be used when unmarshalling * any Parcelable values from the extras of this Intent. @@ -5679,6 +5709,16 @@ public class Intent implements Parcelable, Cloneable { } /** + * This is NOT a secure mechanism to identify the user who sent the intent. + * When the intent is sent to a different user, it is used to fix uris by adding the userId + * who sent the intent. + * @hide + */ + public void setContentUserHint(int contentUserHint) { + mContentUserHint = contentUserHint; + } + + /** * Add extended data to the intent. The name must include a package * prefix, for example the app com.android.contacts would use names * like "com.android.contacts.ShowAll". @@ -6731,6 +6771,7 @@ public class Intent implements Parcelable, Cloneable { @FillInFlags public int fillIn(Intent other, @FillInFlags int flags) { int changes = 0; + boolean mayHaveCopiedUris = false; if (other.mAction != null && (mAction == null || (flags&FILL_IN_ACTION) != 0)) { mAction = other.mAction; @@ -6742,6 +6783,7 @@ public class Intent implements Parcelable, Cloneable { mData = other.mData; mType = other.mType; changes |= FILL_IN_DATA; + mayHaveCopiedUris = true; } if (other.mCategories != null && (mCategories == null || (flags&FILL_IN_CATEGORIES) != 0)) { @@ -6771,6 +6813,7 @@ public class Intent implements Parcelable, Cloneable { && (mClipData == null || (flags&FILL_IN_CLIP_DATA) != 0)) { mClipData = other.mClipData; changes |= FILL_IN_CLIP_DATA; + mayHaveCopiedUris = true; } // Component is special: it can -only- be set if explicitly allowed, // since otherwise the sender could force the intent somewhere the @@ -6788,12 +6831,14 @@ public class Intent implements Parcelable, Cloneable { if (mExtras == null) { if (other.mExtras != null) { mExtras = new Bundle(other.mExtras); + mayHaveCopiedUris = true; } } else if (other.mExtras != null) { try { Bundle newb = new Bundle(other.mExtras); newb.putAll(mExtras); mExtras = newb; + mayHaveCopiedUris = true; } catch (RuntimeException e) { // Modifying the extras can cause us to unparcel the contents // of the bundle, and if we do this in the system process that @@ -6803,6 +6848,10 @@ public class Intent implements Parcelable, Cloneable { Log.w("Intent", "Failure filling in extras", e); } } + if (mayHaveCopiedUris && mContentUserHint == UserHandle.USER_CURRENT + && other.mContentUserHint != UserHandle.USER_CURRENT) { + mContentUserHint = other.mContentUserHint; + } return changes; } @@ -7030,8 +7079,15 @@ public class Intent implements Parcelable, Cloneable { first = false; b.append("(has extras)"); } + if (mContentUserHint != UserHandle.USER_CURRENT) { + if (!first) { + b.append(' '); + } + first = false; + b.append("u=").append(mContentUserHint); + } if (mSelector != null) { - b.append(" sel={"); + b.append(" sel="); mSelector.toShortString(b, secure, comp, extras, clip); b.append("}"); } @@ -7208,7 +7264,7 @@ public class Intent implements Parcelable, Cloneable { } else { out.writeInt(0); } - + out.writeInt(mContentUserHint); out.writeBundle(mExtras); } @@ -7257,7 +7313,7 @@ public class Intent implements Parcelable, Cloneable { if (in.readInt() != 0) { mClipData = new ClipData(in); } - + mContentUserHint = in.readInt(); mExtras = in.readBundle(); } @@ -7467,39 +7523,50 @@ public class Intent implements Parcelable, Cloneable { } /** - * Prepare this {@link Intent} to be sent to another user - * * @hide */ - public void prepareToLeaveUser(int userId) { + public void prepareToEnterProcess() { + if (mContentUserHint != UserHandle.USER_CURRENT) { + fixUris(mContentUserHint); + mContentUserHint = UserHandle.USER_CURRENT; + } + } + + /** + * @hide + */ + public void fixUris(int contentUserHint) { Uri data = getData(); if (data != null) { - mData = maybeAddUserId(data, userId); - } - if (mSelector != null) { - mSelector.prepareToLeaveUser(userId); + mData = maybeAddUserId(data, contentUserHint); } if (mClipData != null) { - mClipData.prepareToLeaveUser(userId); + mClipData.fixUris(contentUserHint); } String action = getAction(); if (ACTION_SEND.equals(action)) { final Uri stream = getParcelableExtra(EXTRA_STREAM); if (stream != null) { - putExtra(EXTRA_STREAM, maybeAddUserId(stream, userId)); + putExtra(EXTRA_STREAM, maybeAddUserId(stream, contentUserHint)); } - } - if (ACTION_SEND_MULTIPLE.equals(action)) { + } else if (ACTION_SEND_MULTIPLE.equals(action)) { final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM); if (streams != null) { ArrayList<Uri> newStreams = new ArrayList<Uri>(); for (int i = 0; i < streams.size(); i++) { - newStreams.add(maybeAddUserId(streams.get(i), userId)); + newStreams.add(maybeAddUserId(streams.get(i), contentUserHint)); } putParcelableArrayListExtra(EXTRA_STREAM, newStreams); } + } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action) + || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action) + || MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) { + final Uri output = getParcelableExtra(MediaStore.EXTRA_OUTPUT); + if (output != null) { + putExtra(MediaStore.EXTRA_OUTPUT, maybeAddUserId(output, contentUserHint)); + } } - } + } /** * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and @@ -7590,6 +7657,20 @@ public class Intent implements Parcelable, Cloneable { } } catch (ClassCastException e) { } + } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action) + || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action) + || MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) { + final Uri output; + try { + output = getParcelableExtra(MediaStore.EXTRA_OUTPUT); + } catch (ClassCastException e) { + return false; + } + if (output != null) { + setClipData(ClipData.newRawUri("", output)); + addFlags(FLAG_GRANT_WRITE_URI_PERMISSION|FLAG_GRANT_READ_URI_PERMISSION); + return true; + } } return false; diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index 0acf0431c6b1..d9005b2ae114 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -35,6 +35,8 @@ interface ILauncherApps { ResolveInfo resolveActivity(in Intent intent, in UserHandle user); void startActivityAsUser(in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); + void showAppDetailsAsUser(in ComponentName component, in Rect sourceBounds, + in Bundle opts, in UserHandle user); boolean isPackageEnabled(String packageName, in UserHandle user); boolean isActivityEnabled(in ComponentName component, in UserHandle user); } diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 32460c93c4e0..0c650349bc91 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -17,7 +17,7 @@ package android.content.pm; import android.content.pm.IPackageDeleteObserver; -import android.content.pm.IPackageInstallerObserver; +import android.content.pm.IPackageInstallerCallback; import android.content.pm.IPackageInstallerSession; import android.content.pm.InstallSessionInfo; import android.content.pm.InstallSessionParams; @@ -25,13 +25,15 @@ import android.os.ParcelFileDescriptor; /** {@hide} */ interface IPackageInstaller { - int createSession(String installerPackageName, in InstallSessionParams params, int userId); + int createSession(in InstallSessionParams params, String installerPackageName, int userId); IPackageInstallerSession openSession(int sessionId); - List<InstallSessionInfo> getSessions(int userId); + InstallSessionInfo getSessionInfo(int sessionId); + List<InstallSessionInfo> getAllSessions(int userId); + List<InstallSessionInfo> getMySessions(String installerPackageName, int userId); - void registerObserver(IPackageInstallerObserver observer, int userId); - void unregisterObserver(IPackageInstallerObserver observer, int userId); + void registerCallback(IPackageInstallerCallback callback, int userId); + void unregisterCallback(IPackageInstallerCallback callback); void uninstall(String packageName, int flags, in IPackageDeleteObserver observer, int userId); void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver observer, int userId); diff --git a/core/java/android/content/pm/IPackageInstallerObserver.aidl b/core/java/android/content/pm/IPackageInstallerCallback.aidl index 85660e4f818b..a31ae54061c5 100644 --- a/core/java/android/content/pm/IPackageInstallerObserver.aidl +++ b/core/java/android/content/pm/IPackageInstallerCallback.aidl @@ -16,11 +16,9 @@ package android.content.pm; -import android.content.pm.InstallSessionInfo; - /** {@hide} */ -oneway interface IPackageInstallerObserver { - void onSessionCreated(in InstallSessionInfo info); - void onSessionProgress(int sessionId, int progress); +oneway interface IPackageInstallerCallback { + void onSessionCreated(int sessionId); + void onSessionProgressChanged(int sessionId, float progress); void onSessionFinished(int sessionId, boolean success); } diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index d6775d4d5d70..2fd7ddbf0661 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -21,11 +21,12 @@ import android.os.ParcelFileDescriptor; /** {@hide} */ interface IPackageInstallerSession { - void setClientProgress(int progress); - void addClientProgress(int progress); + void setClientProgress(float progress); + void addClientProgress(float progress); ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes); - void install(in IPackageInstallObserver2 observer); - void destroy(); + void close(); + void commit(in IPackageInstallObserver2 observer); + void abandon(); } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 4b339a1e1774..7196372edf4f 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -244,13 +244,13 @@ interface IPackageManager { void clearPackagePersistentPreferredActivities(String packageName, int userId); - void addCrossProfileIntentFilter(in IntentFilter intentFilter, int sourceUserId, int targetUserId, - int flags); + void addCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage, + int ownerUserId, int sourceUserId, int targetUserId, int flags); void addCrossProfileIntentsForPackage(in String packageName, int sourceUserId, int targetUserId); - void clearCrossProfileIntentFilters(int sourceUserId); + void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage, int ownerUserId); /** * Report the set of 'Home' activity candidates, plus (if any) which of them @@ -397,6 +397,8 @@ interface IPackageManager { */ boolean performDexOptIfNeeded(String packageName, String instructionSet); + void forceDexOpt(String packageName); + /** * Update status of external media on the package manager to scan and * install packages installed on the external media. Like say the diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java index 33367274ce8e..a9c574a439f7 100644 --- a/core/java/android/content/pm/InstallSessionInfo.java +++ b/core/java/android/content/pm/InstallSessionInfo.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.annotation.Nullable; import android.graphics.Bitmap; import android.os.Parcel; import android.os.Parcelable; @@ -30,16 +31,18 @@ public class InstallSessionInfo implements Parcelable { /** {@hide} */ public String installerPackageName; /** {@hide} */ - public int progress; + public float progress; /** {@hide} */ public int mode; /** {@hide} */ - public String packageName; + public long sizeBytes; /** {@hide} */ - public Bitmap icon; + public String appPackageName; /** {@hide} */ - public CharSequence title; + public Bitmap appIcon; + /** {@hide} */ + public CharSequence appLabel; /** {@hide} */ public InstallSessionInfo() { @@ -49,12 +52,13 @@ public class InstallSessionInfo implements Parcelable { public InstallSessionInfo(Parcel source) { sessionId = source.readInt(); installerPackageName = source.readString(); - progress = source.readInt(); + progress = source.readFloat(); mode = source.readInt(); - packageName = source.readString(); - icon = source.readParcelable(null); - title = source.readString(); + sizeBytes = source.readLong(); + appPackageName = source.readString(); + appIcon = source.readParcelable(null); + appLabel = source.readString(); } /** @@ -67,19 +71,19 @@ public class InstallSessionInfo implements Parcelable { /** * Return the package name of the app that owns this session. */ - public String getInstallerPackageName() { + public @Nullable String getInstallerPackageName() { return installerPackageName; } /** - * Return current overall progress of this session, between 0 and 100. + * Return current overall progress of this session, between 0 and 1. * <p> * Note that this progress may not directly correspond to the value reported - * by {@link PackageInstaller.Session#setProgress(int)}, as the system may + * by {@link PackageInstaller.Session#setProgress(float)}, as the system may * carve out a portion of the overall progress to represent its own internal * installation work. */ - public int getProgress() { + public float getProgress() { return progress; } @@ -87,24 +91,24 @@ public class InstallSessionInfo implements Parcelable { * Return the package name this session is working with. May be {@code null} * if unknown. */ - public String getPackageName() { - return packageName; + public @Nullable String getAppPackageName() { + return appPackageName; } /** * Return an icon representing the app being installed. May be {@code null} * if unavailable. */ - public Bitmap getIcon() { - return icon; + public @Nullable Bitmap getAppIcon() { + return appIcon; } /** - * Return a title representing the app being installed. May be {@code null} + * Return a label representing the app being installed. May be {@code null} * if unavailable. */ - public CharSequence getTitle() { - return title; + public @Nullable CharSequence getAppLabel() { + return appLabel; } @Override @@ -116,12 +120,13 @@ public class InstallSessionInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(sessionId); dest.writeString(installerPackageName); - dest.writeInt(progress); + dest.writeFloat(progress); dest.writeInt(mode); - dest.writeString(packageName); - dest.writeParcelable(icon, flags); - dest.writeString(title != null ? title.toString() : null); + dest.writeLong(sizeBytes); + dest.writeString(appPackageName); + dest.writeParcelable(appIcon, flags); + dest.writeString(appLabel != null ? appLabel.toString() : null); } public static final Parcelable.Creator<InstallSessionInfo> diff --git a/core/java/android/content/pm/InstallSessionParams.java b/core/java/android/content/pm/InstallSessionParams.java index e0396992216e..3de986343242 100644 --- a/core/java/android/content/pm/InstallSessionParams.java +++ b/core/java/android/content/pm/InstallSessionParams.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.annotation.Nullable; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; @@ -29,17 +30,25 @@ import com.android.internal.util.IndentingPrintWriter; */ public class InstallSessionParams implements Parcelable { - // TODO: extend to support remaining VerificationParams - - /** {@hide} */ - public static final int MODE_INVALID = 0; - /** {@hide} */ + /** + * Mode for an install session whose staged APKs should fully replace any + * existing APKs for the target app. + */ public static final int MODE_FULL_INSTALL = 1; - /** {@hide} */ + + /** + * Mode for an install session that should inherit any existing APKs for the + * target app, unless they have been explicitly overridden (based on split + * name) by the session. For example, this can be used to add one or more + * split APKs to an existing installation. + * <p> + * If there are no existing APKs for the target app, this behaves like + * {@link #MODE_FULL_INSTALL}. + */ public static final int MODE_INHERIT_EXISTING = 2; /** {@hide} */ - public int mode = MODE_INVALID; + public int mode; /** {@hide} */ public int installFlags; /** {@hide} */ @@ -47,15 +56,13 @@ public class InstallSessionParams implements Parcelable { /** {@hide} */ public Signature[] signatures; /** {@hide} */ - public long deltaSize = -1; + public long sizeBytes = -1; /** {@hide} */ - public int progressMax = 100; + public String appPackageName; /** {@hide} */ - public String packageName; + public Bitmap appIcon; /** {@hide} */ - public Bitmap icon; - /** {@hide} */ - public CharSequence title; + public CharSequence appLabel; /** {@hide} */ public Uri originatingUri; /** {@hide} */ @@ -63,7 +70,15 @@ public class InstallSessionParams implements Parcelable { /** {@hide} */ public String abiOverride; - public InstallSessionParams() { + /** + * Construct parameters for a new package install session. + * + * @param mode one of {@link #MODE_FULL_INSTALL} or + * {@link #MODE_INHERIT_EXISTING} describing how the session + * should interact with an existing app. + */ + public InstallSessionParams(int mode) { + this.mode = mode; } /** {@hide} */ @@ -72,34 +87,16 @@ public class InstallSessionParams implements Parcelable { installFlags = source.readInt(); installLocation = source.readInt(); signatures = (Signature[]) source.readParcelableArray(null); - deltaSize = source.readLong(); - progressMax = source.readInt(); - packageName = source.readString(); - icon = source.readParcelable(null); - title = source.readString(); + sizeBytes = source.readLong(); + appPackageName = source.readString(); + appIcon = source.readParcelable(null); + appLabel = source.readString(); originatingUri = source.readParcelable(null); referrerUri = source.readParcelable(null); abiOverride = source.readString(); } /** - * Set session mode indicating that it should fully replace any existing - * APKs for this application. - */ - public void setModeFullInstall() { - this.mode = MODE_FULL_INSTALL; - } - - /** - * Set session mode indicating that it should inherit any existing APKs for - * this application, unless they are explicitly overridden (by split name) - * in the session. - */ - public void setModeInheritExisting() { - this.mode = MODE_INHERIT_EXISTING; - } - - /** * Provide value of {@link PackageInfo#installLocation}, which may be used * to determine where the app will be staged. Defaults to * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}. @@ -109,56 +106,57 @@ public class InstallSessionParams implements Parcelable { } /** - * Optionally provide the required value of {@link PackageInfo#signatures}. - * This can be used to assert that all staged APKs have been signed with - * this set of specific certificates. Regardless of this value, all APKs in - * the application must have the same signing certificates. - */ - public void setSignatures(Signature[] signatures) { - this.signatures = signatures; - } - - /** - * Indicate the expected growth in disk usage resulting from this session. - * This may be used to ensure enough disk space exists before proceeding, or - * to estimate container size for installations living on external storage. + * Optionally provide a set of certificates for the app being installed. * <p> - * This value should only reflect APK sizes. + * If the APKs staged in the session aren't consistent with these + * signatures, the install will fail. Regardless of this value, all APKs in + * the app must have the same signing certificates. + * + * @see PackageInfo#signatures */ - public void setDeltaSize(long deltaSize) { - this.deltaSize = deltaSize; + public void setSignatures(@Nullable Signature[] signatures) { + this.signatures = signatures; } /** - * Set the maximum progress for this session, used for normalization - * purposes. + * Optionally indicate the total size (in bytes) of all APKs that will be + * delivered in this session. The system may use this to ensure enough disk + * space exists before proceeding, or to estimate container size for + * installations living on external storage. * - * @see PackageInstaller.Session#setProgress(int) + * @see PackageInfo#INSTALL_LOCATION_AUTO + * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL */ - public void setProgressMax(int progressMax) { - this.progressMax = progressMax; + public void setSize(long sizeBytes) { + this.sizeBytes = sizeBytes; } /** - * Optionally set the package name this session will be working with. It's - * strongly recommended that you provide this value when known. + * Optionally set the package name of the app being installed. It's strongly + * recommended that you provide this value when known, so that observers can + * communicate installing apps to users. + * <p> + * If the APKs staged in the session aren't consistent with this package + * name, the install will fail. Regardless of this value, all APKs in the + * app must have the same package name. */ - public void setPackageName(String packageName) { - this.packageName = packageName; + public void setAppPackageName(@Nullable String appPackageName) { + this.appPackageName = appPackageName; } /** - * Optionally set an icon representing the app being installed. + * Optionally set an icon representing the app being installed. This should + * be at least {@link android.R.dimen#app_icon_size} in both dimensions. */ - public void setIcon(Bitmap icon) { - this.icon = icon; + public void setAppIcon(@Nullable Bitmap appIcon) { + this.appIcon = appIcon; } /** - * Optionally set a title representing the app being installed. + * Optionally set a label representing the app being installed. */ - public void setTitle(CharSequence title) { - this.title = title; + public void setAppLabel(@Nullable CharSequence appLabel) { + this.appLabel = appLabel; } /** @@ -167,7 +165,7 @@ public class InstallSessionParams implements Parcelable { * * @see Intent#EXTRA_ORIGINATING_URI */ - public void setOriginatingUri(Uri originatingUri) { + public void setOriginatingUri(@Nullable Uri originatingUri) { this.originatingUri = originatingUri; } @@ -177,7 +175,7 @@ public class InstallSessionParams implements Parcelable { * * @see Intent#EXTRA_REFERRER */ - public void setReferrerUri(Uri referrerUri) { + public void setReferrerUri(@Nullable Uri referrerUri) { this.referrerUri = referrerUri; } @@ -187,11 +185,10 @@ public class InstallSessionParams implements Parcelable { pw.printHexPair("installFlags", installFlags); pw.printPair("installLocation", installLocation); pw.printPair("signatures", (signatures != null)); - pw.printPair("deltaSize", deltaSize); - pw.printPair("progressMax", progressMax); - pw.printPair("packageName", packageName); - pw.printPair("icon", (icon != null)); - pw.printPair("title", title); + pw.printPair("sizeBytes", sizeBytes); + pw.printPair("appPackageName", appPackageName); + pw.printPair("appIcon", (appIcon != null)); + pw.printPair("appLabel", appLabel); pw.printPair("originatingUri", originatingUri); pw.printPair("referrerUri", referrerUri); pw.printPair("abiOverride", abiOverride); @@ -209,11 +206,10 @@ public class InstallSessionParams implements Parcelable { dest.writeInt(installFlags); dest.writeInt(installLocation); dest.writeParcelableArray(signatures, flags); - dest.writeLong(deltaSize); - dest.writeInt(progressMax); - dest.writeString(packageName); - dest.writeParcelable(icon, flags); - dest.writeString(title != null ? title.toString() : null); + dest.writeLong(sizeBytes); + dest.writeString(appPackageName); + dest.writeParcelable(appIcon, flags); + dest.writeString(appLabel != null ? appLabel.toString() : null); dest.writeParcelable(originatingUri, flags); dest.writeParcelable(referrerUri, flags); dest.writeString(abiOverride); diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 6e7a41832320..2d50b5aa6ffb 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -230,6 +230,24 @@ public class LauncherApps { } /** + * Starts the settings activity to show the application details for a + * package in the specified profile. + * + * @param component The ComponentName of the package to launch settings for. + * @param user The UserHandle of the profile + * @param sourceBounds The Rect containing the source bounds of the clicked icon + * @param opts Options to pass to startActivity + */ + public void showAppDetailsForProfile(ComponentName component, UserHandle user, + Rect sourceBounds, Bundle opts) { + try { + mService.showAppDetailsAsUser(component, sourceBounds, opts, user); + } catch (RemoteException re) { + // Oops! + } + } + + /** * Checks if the package is installed and enabled for a profile. * * @param packageName The package to check. diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index df82d264d1bb..a114bb894084 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -16,11 +16,16 @@ package android.content.pm; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.PackageInstallObserver; import android.app.PackageUninstallObserver; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.FileBridge; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.ExceptionUtils; @@ -28,6 +33,8 @@ import android.util.ExceptionUtils; import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; import java.util.List; /** @@ -61,6 +68,8 @@ public class PackageInstaller { private final int mUserId; private final String mInstallerPackageName; + private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>(); + /** {@hide} */ public PackageInstaller(PackageManager pm, IPackageInstaller installer, String installerPackageName, int userId) { @@ -71,28 +80,6 @@ public class PackageInstaller { } /** - * Quickly test if the given package is already available on the device. - * This is typically used in multi-user scenarios where another user on the - * device has already installed the package. - * - * @hide - */ - public boolean isPackageAvailable(String packageName) { - return mPm.isPackageAvailable(packageName); - } - - /** {@hide} */ - public void installAvailablePackage(String packageName, PackageInstallObserver observer) { - int returnCode; - try { - returnCode = mPm.installExistingPackage(packageName); - } catch (NameNotFoundException e) { - returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED; - } - observer.packageInstalled(packageName, null, returnCode); - } - - /** * Create a new session using the given parameters, returning a unique ID * that represents the session. Once created, the session can be opened * multiple times across multiple device boots. @@ -104,9 +91,9 @@ public class PackageInstaller { * @throws IOException if parameters were unsatisfiable, such as lack of * disk space or unavailable media. */ - public int createSession(InstallSessionParams params) throws IOException { + public int createSession(@NonNull InstallSessionParams params) throws IOException { try { - return mInstaller.createSession(mInstallerPackageName, params, mUserId); + return mInstaller.createSession(params, mInstallerPackageName, mUserId); } catch (RuntimeException e) { ExceptionUtils.maybeUnwrapIOException(e); throw e; @@ -116,9 +103,10 @@ public class PackageInstaller { } /** - * Open an existing session to actively perform work. + * Open an existing session to actively perform work. To succeed, the caller + * must be the owner of the install session. */ - public Session openSession(int sessionId) { + public @NonNull Session openSession(int sessionId) { try { return new Session(mInstaller.openSession(sessionId)); } catch (RemoteException e) { @@ -127,13 +115,35 @@ public class PackageInstaller { } /** - * Return list of all active install sessions on the device. + * Return details for a specific session. To succeed, the caller must either + * own this session, or be the current home app. */ - public List<InstallSessionInfo> getActiveSessions() { - // TODO: filter based on caller - // TODO: let launcher app see all active sessions + public @Nullable InstallSessionInfo getSessionInfo(int sessionId) { try { - return mInstaller.getSessions(mUserId); + return mInstaller.getSessionInfo(sessionId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Return list of all active install sessions, regardless of the installer. + * To succeed, the caller must be the current home app. + */ + public @NonNull List<InstallSessionInfo> getAllSessions() { + try { + return mInstaller.getAllSessions(mUserId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Return list of all install sessions owned by the calling app. + */ + public @NonNull List<InstallSessionInfo> getMySessions() { + try { + return mInstaller.getMySessions(mInstallerPackageName, mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -144,10 +154,10 @@ public class PackageInstaller { * method is only available to the current "installer of record" for the * package. */ - public void uninstall(String packageName, UninstallResultCallback callback) { + public void uninstall(@NonNull String packageName, @NonNull UninstallCallback callback) { try { mInstaller.uninstall(packageName, 0, - new UninstallResultCallbackDelegate(callback).getBinder(), mUserId); + new UninstallCallbackDelegate(callback).getBinder(), mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -158,10 +168,11 @@ public class PackageInstaller { * * @hide */ - public void uninstall(String packageName, String splitName, UninstallResultCallback callback) { + public void uninstall(@NonNull String packageName, @NonNull String splitName, + @NonNull UninstallCallback callback) { try { mInstaller.uninstallSplit(packageName, splitName, 0, - new UninstallResultCallbackDelegate(callback).getBinder(), mUserId); + new UninstallCallbackDelegate(callback).getBinder(), mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -170,69 +181,121 @@ public class PackageInstaller { /** * Events for observing session lifecycle. */ - public static abstract class SessionObserver { - private final IPackageInstallerObserver.Stub mBinder = new IPackageInstallerObserver.Stub() { - @Override - public void onSessionCreated(InstallSessionInfo info) { - SessionObserver.this.onCreated(info); - } - - @Override - public void onSessionProgress(int sessionId, int progress) { - SessionObserver.this.onProgress(sessionId, progress); - } - - @Override - public void onSessionFinished(int sessionId, boolean success) { - SessionObserver.this.onFinalized(sessionId, success); - } - }; - - /** {@hide} */ - public IPackageInstallerObserver getBinder() { - return mBinder; - } - + public static abstract class SessionCallback { /** * New session has been created. */ - public abstract void onCreated(InstallSessionInfo info); + public abstract void onCreated(int sessionId); /** * Progress for given session has been updated. * <p> * Note that this progress may not directly correspond to the value - * reported by {@link PackageInstaller.Session#setProgress(int)}, as the - * system may carve out a portion of the overall progress to represent - * its own internal installation work. + * reported by {@link PackageInstaller.Session#setProgress(float)}, as + * the system may carve out a portion of the overall progress to + * represent its own internal installation work. */ - public abstract void onProgress(int sessionId, int progress); + public abstract void onProgressChanged(int sessionId, float progress); /** - * Session has been finalized, either with success or failure. + * Session has completely finished, either with success or failure. */ - public abstract void onFinalized(int sessionId, boolean success); + public abstract void onFinished(int sessionId, boolean success); + } + + /** {@hide} */ + private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements + Handler.Callback { + private static final int MSG_SESSION_CREATED = 1; + private static final int MSG_SESSION_PROGRESS_CHANGED = 2; + private static final int MSG_SESSION_FINISHED = 3; + + final SessionCallback mCallback; + final Handler mHandler; + + public SessionCallbackDelegate(SessionCallback callback, Looper looper) { + mCallback = callback; + mHandler = new Handler(looper, this); + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_SESSION_CREATED: + mCallback.onCreated(msg.arg1); + return true; + case MSG_SESSION_PROGRESS_CHANGED: + mCallback.onProgressChanged(msg.arg1, (float) msg.obj); + return true; + case MSG_SESSION_FINISHED: + mCallback.onFinished(msg.arg1, msg.arg2 != 0); + return true; + } + return false; + } + + @Override + public void onSessionCreated(int sessionId) { + mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget(); + } + + @Override + public void onSessionProgressChanged(int sessionId, float progress) { + mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress) + .sendToTarget(); + } + + @Override + public void onSessionFinished(int sessionId, boolean success) { + mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0) + .sendToTarget(); + } } /** - * Register to watch for session lifecycle events. + * Register to watch for session lifecycle events. To succeed, the caller + * must be the current home app. */ - public void registerSessionObserver(SessionObserver observer) { - try { - mInstaller.registerObserver(observer.getBinder(), mUserId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + public void addSessionCallback(@NonNull SessionCallback callback) { + addSessionCallback(callback, new Handler()); + } + + /** + * Register to watch for session lifecycle events. To succeed, the caller + * must be the current home app. + * + * @param handler to dispatch callback events through, otherwise uses + * calling thread. + */ + public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { + synchronized (mDelegates) { + final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, + handler.getLooper()); + try { + mInstaller.registerCallback(delegate, mUserId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + mDelegates.add(delegate); } } /** - * Unregister an existing observer. + * Unregister an existing callback. */ - public void unregisterSessionObserver(SessionObserver observer) { - try { - mInstaller.unregisterObserver(observer.getBinder(), mUserId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + public void removeSessionCallback(@NonNull SessionCallback callback) { + synchronized (mDelegates) { + for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { + final SessionCallbackDelegate delegate = i.next(); + if (delegate.mCallback == callback) { + try { + mInstaller.unregisterCallback(delegate); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + i.remove(); + } + } } } @@ -244,9 +307,9 @@ public class PackageInstaller { * A session may contain any number of split packages. If the application * does not yet exist, this session must include a base package. * <p> - * If a package included in this session is already defined by the existing - * installation (for example, the same split name), the package in this - * session will replace the existing package. + * If an APK included in this session is already defined by the existing + * installation (for example, the same split name), the APK in this session + * will replace the existing APK. */ public static class Session implements Closeable { private IPackageInstallerSession mSession; @@ -257,10 +320,9 @@ public class PackageInstaller { } /** - * Set current progress. Valid values are anywhere between 0 and - * {@link InstallSessionParams#setProgressMax(int)}. + * Set current progress. Valid values are anywhere between 0 and 1. */ - public void setProgress(int progress) { + public void setProgress(float progress) { try { mSession.setClientProgress(progress); } catch (RemoteException e) { @@ -269,7 +331,7 @@ public class PackageInstaller { } /** {@hide} */ - public void addProgress(int progress) { + public void addProgress(float progress) { try { mSession.addClientProgress(progress); } catch (RemoteException e) { @@ -278,15 +340,33 @@ public class PackageInstaller { } /** - * Open an APK file for writing, starting at the given offset. You can - * then stream data into the file, periodically calling - * {@link #fsync(OutputStream)} to ensure bytes have been written to - * disk. + * Open a stream to write an APK file into the session. + * <p> + * The returned stream will start writing data at the requested offset + * in the underlying file, which can be used to resume a partially + * written file. If a valid file length is specified, the system will + * preallocate the underlying disk space to optimize placement on disk. + * It's strongly recommended to provide a valid file length when known. + * <p> + * You can write data into the returned stream, optionally call + * {@link #fsync(OutputStream)} as needed to ensure bytes have been + * persisted to disk, and then close when finished. All streams must be + * closed before calling {@link #commit(CommitCallback)}. + * + * @param name arbitrary, unique name of your choosing to identify the + * APK being written. You can open a file again for + * additional writes (such as after a reboot) by using the + * same name. This name is only meaningful within the context + * of a single install session. + * @param offsetBytes offset into the file to begin writing at, or 0 to + * start at the beginning of the file. + * @param lengthBytes total size of the file being written, used to + * preallocate the underlying disk space, or -1 if unknown. */ - public OutputStream openWrite(String splitName, long offsetBytes, long lengthBytes) - throws IOException { + public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes, + long lengthBytes) throws IOException { try { - final ParcelFileDescriptor clientSocket = mSession.openWrite(splitName, + final ParcelFileDescriptor clientSocket = mSession.openWrite(name, offsetBytes, lengthBytes); return new FileBridge.FileBridgeOutputStream(clientSocket.getFileDescriptor()); } catch (RuntimeException e) { @@ -302,7 +382,7 @@ public class PackageInstaller { * to disk. This is only valid for streams returned from * {@link #openWrite(String, long, long)}. */ - public void fsync(OutputStream out) throws IOException { + public void fsync(@NonNull OutputStream out) throws IOException { if (out instanceof FileBridge.FileBridgeOutputStream) { ((FileBridge.FileBridgeOutputStream) out).fsync(); } else { @@ -319,9 +399,9 @@ public class PackageInstaller { * on the session. If the device reboots before the session has been * finalized, you may commit the session again. */ - public void commit(CommitResultCallback callback) { + public void commit(@NonNull CommitCallback callback) { try { - mSession.install(new CommitResultCallbackDelegate(callback).getBinder()); + mSession.commit(new CommitCallbackDelegate(callback).getBinder()); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -333,15 +413,20 @@ public class PackageInstaller { */ @Override public void close() { - // No resources to release at the moment + try { + mSession.close(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } } /** - * Completely destroy this session, rendering it invalid. + * Completely abandon this session, destroying all staged data and + * rendering it invalid. */ - public void destroy() { + public void abandon() { try { - mSession.destroy(); + mSession.abandon(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -351,30 +436,26 @@ public class PackageInstaller { /** * Final result of an uninstall request. */ - public static abstract class UninstallResultCallback { + public static abstract class UninstallCallback { public abstract void onSuccess(); public abstract void onFailure(String msg); } /** {@hide} */ - private static class UninstallResultCallbackDelegate extends PackageUninstallObserver { - private final UninstallResultCallback target; + private static class UninstallCallbackDelegate extends PackageUninstallObserver { + private final UninstallCallback target; - public UninstallResultCallbackDelegate(UninstallResultCallback target) { + public UninstallCallbackDelegate(UninstallCallback target) { this.target = target; } @Override public void onUninstallFinished(String basePackageName, int returnCode) { - final String msg = null; - - switch (returnCode) { - case PackageManager.DELETE_SUCCEEDED: target.onSuccess(); break; - case PackageManager.DELETE_FAILED_INTERNAL_ERROR: target.onFailure("DELETE_FAILED_INTERNAL_ERROR: " + msg); break; - case PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER: target.onFailure("DELETE_FAILED_DEVICE_POLICY_MANAGER: " + msg); break; - case PackageManager.DELETE_FAILED_USER_RESTRICTED: target.onFailure("DELETE_FAILED_USER_RESTRICTED: " + msg); break; - case PackageManager.DELETE_FAILED_OWNER_BLOCKED: target.onFailure("DELETE_FAILED_OWNER_BLOCKED: " + msg); break; - default: target.onFailure(msg); break; + if (returnCode == PackageManager.DELETE_SUCCEEDED) { + target.onSuccess(); + } else { + final String msg = PackageManager.deleteStatusToString(returnCode); + target.onFailure(msg); } } } @@ -382,16 +463,13 @@ public class PackageInstaller { /** * Final result of a session commit request. */ - public static abstract class CommitResultCallback { - public abstract void onSuccess(); - + public static abstract class CommitCallback { /** - * Generic failure occurred. You can override methods (such as - * {@link #onFailureInvalid(String)}) to handle more specific categories - * of failure. By default, those specific categories all flow into this - * generic failure. + * Generic unknown failure. The system will always try to provide a more + * specific failure reason, but in some rare cases this may be + * delivered. */ - public abstract void onFailure(String msg); + public static final int FAILURE_UNKNOWN = 0; /** * One or more of the APKs included in the session was invalid. For @@ -399,23 +477,19 @@ public class PackageInstaller { * mismatched, etc. The installer may want to try downloading and * installing again. */ - public void onFailureInvalid(String msg) { - onFailure(msg); - } + public static final int FAILURE_INVALID = 1; /** * This install session conflicts (or is inconsistent with) with another * package already installed on the device. For example, an existing * permission, incompatible certificates, etc. The user may be able to * uninstall another app to fix the issue. - * - * @param otherPackageName if one specific package was identified as the - * cause of the conflict, it's named here. If unknown, or - * multiple packages, this may be {@code null}. + * <p> + * The extras bundle may contain {@link #EXTRA_PACKAGE_NAME} if one + * specific package was identified as the cause of the conflict. If + * unknown, or multiple packages, the extra may be {@code null}. */ - public void onFailureConflict(String msg, String otherPackageName) { - onFailure(msg); - } + public static final int FAILURE_CONFLICT = 2; /** * This install session failed due to storage issues. For example, @@ -423,9 +497,7 @@ public class PackageInstaller { * media may be unavailable. The user may be able to help free space * or insert the correct media. */ - public void onFailureStorage(String msg) { - onFailure(msg); - } + public static final int FAILURE_STORAGE = 3; /** * This install session is fundamentally incompatible with this @@ -434,66 +506,37 @@ public class PackageInstaller { * ABI, or it requires a newer SDK version, etc. This install would * never succeed. */ - public void onFailureIncompatible(String msg) { - onFailure(msg); - } + public static final int FAILURE_INCOMPATIBLE = 4; + + public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; + + public abstract void onSuccess(); + public abstract void onFailure(int failureReason, String msg, Bundle extras); } /** {@hide} */ - private static class CommitResultCallbackDelegate extends PackageInstallObserver { - private final CommitResultCallback target; + private static class CommitCallbackDelegate extends PackageInstallObserver { + private final CommitCallback target; - public CommitResultCallbackDelegate(CommitResultCallback target) { + public CommitCallbackDelegate(CommitCallback target) { this.target = target; } @Override public void packageInstalled(String basePackageName, Bundle extras, int returnCode, String msg) { - final String otherPackage = null; - - switch (returnCode) { - case PackageManager.INSTALL_SUCCEEDED: target.onSuccess(); break; - case PackageManager.INSTALL_FAILED_ALREADY_EXISTS: target.onFailureConflict("INSTALL_FAILED_ALREADY_EXISTS: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_INVALID_APK: target.onFailureInvalid("INSTALL_FAILED_INVALID_APK: " + msg); break; - case PackageManager.INSTALL_FAILED_INVALID_URI: target.onFailureInvalid("INSTALL_FAILED_INVALID_URI: " + msg); break; - case PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE: target.onFailureStorage("INSTALL_FAILED_INSUFFICIENT_STORAGE: " + msg); break; - case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE: target.onFailureConflict("INSTALL_FAILED_DUPLICATE_PACKAGE: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_NO_SHARED_USER: target.onFailureConflict("INSTALL_FAILED_NO_SHARED_USER: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE: target.onFailureConflict("INSTALL_FAILED_UPDATE_INCOMPATIBLE: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: target.onFailureConflict("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY: target.onFailureIncompatible("INSTALL_FAILED_MISSING_SHARED_LIBRARY: " + msg); break; - case PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE: target.onFailureConflict("INSTALL_FAILED_REPLACE_COULDNT_DELETE: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_DEXOPT: target.onFailureInvalid("INSTALL_FAILED_DEXOPT: " + msg); break; - case PackageManager.INSTALL_FAILED_OLDER_SDK: target.onFailureIncompatible("INSTALL_FAILED_OLDER_SDK: " + msg); break; - case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER: target.onFailureConflict("INSTALL_FAILED_CONFLICTING_PROVIDER: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_NEWER_SDK: target.onFailureIncompatible("INSTALL_FAILED_NEWER_SDK: " + msg); break; - case PackageManager.INSTALL_FAILED_TEST_ONLY: target.onFailureInvalid("INSTALL_FAILED_TEST_ONLY: " + msg); break; - case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: target.onFailureIncompatible("INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: " + msg); break; - case PackageManager.INSTALL_FAILED_MISSING_FEATURE: target.onFailureIncompatible("INSTALL_FAILED_MISSING_FEATURE: " + msg); break; - case PackageManager.INSTALL_FAILED_CONTAINER_ERROR: target.onFailureStorage("INSTALL_FAILED_CONTAINER_ERROR: " + msg); break; - case PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION: target.onFailureStorage("INSTALL_FAILED_INVALID_INSTALL_LOCATION: " + msg); break; - case PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE: target.onFailureStorage("INSTALL_FAILED_MEDIA_UNAVAILABLE: " + msg); break; - case PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT: target.onFailure("INSTALL_FAILED_VERIFICATION_TIMEOUT: " + msg); break; - case PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE: target.onFailure("INSTALL_FAILED_VERIFICATION_FAILURE: " + msg); break; - case PackageManager.INSTALL_FAILED_PACKAGE_CHANGED: target.onFailureInvalid("INSTALL_FAILED_PACKAGE_CHANGED: " + msg); break; - case PackageManager.INSTALL_FAILED_UID_CHANGED: target.onFailureInvalid("INSTALL_FAILED_UID_CHANGED: " + msg); break; - case PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE: target.onFailureInvalid("INSTALL_FAILED_VERSION_DOWNGRADE: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_NOT_APK: target.onFailureInvalid("INSTALL_PARSE_FAILED_NOT_APK: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_MANIFEST: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: target.onFailureInvalid("INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES: target.onFailureInvalid("INSTALL_PARSE_FAILED_NO_CERTIFICATES: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: target.onFailureInvalid("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: target.onFailureInvalid("INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: target.onFailureInvalid("INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY: target.onFailureInvalid("INSTALL_PARSE_FAILED_MANIFEST_EMPTY: " + msg); break; - case PackageManager.INSTALL_FAILED_INTERNAL_ERROR: target.onFailure("INSTALL_FAILED_INTERNAL_ERROR: " + msg); break; - case PackageManager.INSTALL_FAILED_USER_RESTRICTED: target.onFailureIncompatible("INSTALL_FAILED_USER_RESTRICTED: " + msg); break; - case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: target.onFailureConflict("INSTALL_FAILED_DUPLICATE_PERMISSION: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS: target.onFailureInvalid("INSTALL_FAILED_NO_MATCHING_ABIS: " + msg); break; - default: target.onFailure(msg); break; + if (returnCode == PackageManager.INSTALL_SUCCEEDED) { + target.onSuccess(); + } else { + final int failureReason = PackageManager.installStatusToFailureReason(returnCode); + msg = PackageManager.installStatusToString(returnCode) + ": " + msg; + + if (extras != null) { + extras.putString(CommitCallback.EXTRA_PACKAGE_NAME, + extras.getString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE)); + } + + target.onFailure(failureReason, msg, extras); } } } diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java index 9f79a8915939..4b5bdda92ded 100644 --- a/core/java/android/content/pm/PackageItemInfo.java +++ b/core/java/android/content/pm/PackageItemInfo.java @@ -152,15 +152,9 @@ public class PackageItemInfo { * such as the default activity icon. */ public Drawable loadIcon(PackageManager pm) { - if (icon != 0 || showUserIcon != UserHandle.USER_NULL) { - Drawable dr = pm.loadItemIcon(this, getApplicationInfo()); - if (dr != null) { - return dr; - } - } - return loadDefaultIcon(pm); + return pm.loadItemIcon(this, getApplicationInfo()); } - + /** * Retrieve the current graphical banner associated with this item. This * will call back on the given PackageManager to load the banner from diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 8b6ae41d628c..c5dcd8ea5786 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -17,6 +17,7 @@ package android.content.pm; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -26,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; +import android.content.pm.PackageInstaller.CommitCallback; import android.content.pm.PackageParser.PackageParserException; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -203,13 +205,6 @@ public abstract class PackageManager { public static final int NO_CROSS_PROFILE = 0x00020000; /** - * Flag for {@link addCrossProfileIntentFilter}: if the cross-profile intent has been set by the - * profile owner. - * @hide - */ - public static final int SET_BY_PROFILE_OWNER= 0x00000001; - - /** * Flag for {@link addCrossProfileIntentFilter}: if this flag is set: * when resolving an intent that matches the {@link CrossProfileIntentFilter}, the current * profile will be skipped. @@ -3723,7 +3718,7 @@ public abstract class PackageManager { * Return interface that offers the ability to install, upgrade, and remove * applications on the device. */ - public abstract PackageInstaller getInstaller(); + public abstract @NonNull PackageInstaller getPackageInstaller(); /** * Returns the data directory for a particular user and package, given the uid of the package. @@ -3742,9 +3737,10 @@ public abstract class PackageManager { * Adds a {@link CrossProfileIntentFilter}. After calling this method all intents sent from the * user with id sourceUserId can also be be resolved by activities in the user with id * targetUserId if they match the specified intent filter. - * @param filter the {@link IntentFilter} the intent has to match - * @param removable if set to false, {@link clearCrossProfileIntentFilters} will not remove this - * {@link CrossProfileIntentFilter} + * @param filter The {@link IntentFilter} the intent has to match + * @param sourceUserId The source user id. + * @param targetUserId The target user id. + * @param flags The only possible value is {@link SKIP_CURRENT_PROFILE} * @hide */ public abstract void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, @@ -3752,8 +3748,8 @@ public abstract class PackageManager { /** * Clearing {@link CrossProfileIntentFilter}s which have the specified user as their - * source, and have been set by the profile owner - * @param sourceUserId + * source, and have been set by the app calling this method. + * @param sourceUserId The source user id. * @hide */ public abstract void clearCrossProfileIntentFilters(int sourceUserId); @@ -3772,4 +3768,109 @@ public abstract class PackageManager { /** {@hide} */ public abstract boolean isPackageAvailable(String packageName); + + /** {@hide} */ + public static String installStatusToString(int status) { + switch (status) { + case INSTALL_SUCCEEDED: return "INSTALL_SUCCEEDED"; + case INSTALL_FAILED_ALREADY_EXISTS: return "INSTALL_FAILED_ALREADY_EXISTS"; + case INSTALL_FAILED_INVALID_APK: return "INSTALL_FAILED_INVALID_APK"; + case INSTALL_FAILED_INVALID_URI: return "INSTALL_FAILED_INVALID_URI"; + case INSTALL_FAILED_INSUFFICIENT_STORAGE: return "INSTALL_FAILED_INSUFFICIENT_STORAGE"; + case INSTALL_FAILED_DUPLICATE_PACKAGE: return "INSTALL_FAILED_DUPLICATE_PACKAGE"; + case INSTALL_FAILED_NO_SHARED_USER: return "INSTALL_FAILED_NO_SHARED_USER"; + case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return "INSTALL_FAILED_UPDATE_INCOMPATIBLE"; + case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return "INSTALL_FAILED_SHARED_USER_INCOMPATIBLE"; + case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return "INSTALL_FAILED_MISSING_SHARED_LIBRARY"; + case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return "INSTALL_FAILED_REPLACE_COULDNT_DELETE"; + case INSTALL_FAILED_DEXOPT: return "INSTALL_FAILED_DEXOPT"; + case INSTALL_FAILED_OLDER_SDK: return "INSTALL_FAILED_OLDER_SDK"; + case INSTALL_FAILED_CONFLICTING_PROVIDER: return "INSTALL_FAILED_CONFLICTING_PROVIDER"; + case INSTALL_FAILED_NEWER_SDK: return "INSTALL_FAILED_NEWER_SDK"; + case INSTALL_FAILED_TEST_ONLY: return "INSTALL_FAILED_TEST_ONLY"; + case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return "INSTALL_FAILED_CPU_ABI_INCOMPATIBLE"; + case INSTALL_FAILED_MISSING_FEATURE: return "INSTALL_FAILED_MISSING_FEATURE"; + case INSTALL_FAILED_CONTAINER_ERROR: return "INSTALL_FAILED_CONTAINER_ERROR"; + case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return "INSTALL_FAILED_INVALID_INSTALL_LOCATION"; + case INSTALL_FAILED_MEDIA_UNAVAILABLE: return "INSTALL_FAILED_MEDIA_UNAVAILABLE"; + case INSTALL_FAILED_VERIFICATION_TIMEOUT: return "INSTALL_FAILED_VERIFICATION_TIMEOUT"; + case INSTALL_FAILED_VERIFICATION_FAILURE: return "INSTALL_FAILED_VERIFICATION_FAILURE"; + case INSTALL_FAILED_PACKAGE_CHANGED: return "INSTALL_FAILED_PACKAGE_CHANGED"; + case INSTALL_FAILED_UID_CHANGED: return "INSTALL_FAILED_UID_CHANGED"; + case INSTALL_FAILED_VERSION_DOWNGRADE: return "INSTALL_FAILED_VERSION_DOWNGRADE"; + case INSTALL_PARSE_FAILED_NOT_APK: return "INSTALL_PARSE_FAILED_NOT_APK"; + case INSTALL_PARSE_FAILED_BAD_MANIFEST: return "INSTALL_PARSE_FAILED_BAD_MANIFEST"; + case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return "INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION"; + case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return "INSTALL_PARSE_FAILED_NO_CERTIFICATES"; + case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return "INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES"; + case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return "INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING"; + case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return "INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME"; + case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return "INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID"; + case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return "INSTALL_PARSE_FAILED_MANIFEST_MALFORMED"; + case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return "INSTALL_PARSE_FAILED_MANIFEST_EMPTY"; + case INSTALL_FAILED_INTERNAL_ERROR: return "INSTALL_FAILED_INTERNAL_ERROR"; + case INSTALL_FAILED_USER_RESTRICTED: return "INSTALL_FAILED_USER_RESTRICTED"; + case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION"; + case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS"; + default: return Integer.toString(status); + } + } + + /** {@hide} */ + public static int installStatusToFailureReason(int status) { + switch (status) { + case INSTALL_FAILED_ALREADY_EXISTS: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_INVALID_APK: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_INVALID_URI: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_INSUFFICIENT_STORAGE: return CommitCallback.FAILURE_STORAGE; + case INSTALL_FAILED_DUPLICATE_PACKAGE: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_NO_SHARED_USER: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_DEXOPT: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_OLDER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_CONFLICTING_PROVIDER: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_NEWER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_TEST_ONLY: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_MISSING_FEATURE: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_CONTAINER_ERROR: return CommitCallback.FAILURE_STORAGE; + case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return CommitCallback.FAILURE_STORAGE; + case INSTALL_FAILED_MEDIA_UNAVAILABLE: return CommitCallback.FAILURE_STORAGE; + case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_UNKNOWN; + case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_UNKNOWN; + case INSTALL_FAILED_PACKAGE_CHANGED: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_UID_CHANGED: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_VERSION_DOWNGRADE: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_NOT_APK: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_MANIFEST: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_INTERNAL_ERROR: return CommitCallback.FAILURE_UNKNOWN; + case INSTALL_FAILED_USER_RESTRICTED: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_DUPLICATE_PERMISSION: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_NO_MATCHING_ABIS: return CommitCallback.FAILURE_INCOMPATIBLE; + default: return CommitCallback.FAILURE_UNKNOWN; + } + } + + /** {@hide} */ + public static String deleteStatusToString(int status) { + switch (status) { + case DELETE_SUCCEEDED: return "DELETE_SUCCEEDED"; + case DELETE_FAILED_INTERNAL_ERROR: return "DELETE_FAILED_INTERNAL_ERROR"; + case DELETE_FAILED_DEVICE_POLICY_MANAGER: return "DELETE_FAILED_DEVICE_POLICY_MANAGER"; + case DELETE_FAILED_USER_RESTRICTED: return "DELETE_FAILED_USER_RESTRICTED"; + case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED"; + default: return Integer.toString(status); + } + } } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 9866200f80f2..db87cf79de82 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1530,6 +1530,11 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("feature-group")) { + // Skip this for now until we know what to do with it. + + XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("uses-sdk")) { if (SDK_VERSION > 0) { sa = res.obtainAttributes(attrs, diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index a5c2f6359538..b6d2a13f29b4 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -781,6 +781,25 @@ public final class Sensor { */ public static final String STRING_TYPE_GLANCE_GESTURE = "android.sensor.glance_gesture"; + /** + * A constant describing a pick up sensor. + * + * A sensor of this type triggers when the device is picked up regardless of wherever it was + * before (desk, pocket, bag). The only allowed return value is 1.0. This sensor deactivates + * itself immediately after it triggers. + * + * @hide Expected to be used internally for always on display. + */ + public static final int TYPE_PICK_UP_GESTURE = 44; + + /** + * A constant string describing a pick up sensor. + * + * @hide This sensor is expected to be used internally for always on display. + * @see #TYPE_PICK_UP_GESTURE + */ + public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture"; + /** * A constant describing all sensor types. */ @@ -880,6 +899,7 @@ public final class Sensor { 1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR 1, // SENSOR_TYPE_WAKE_GESTURE 1, // SENSOR_TYPE_GLANCE_GESTURE + 1, // SENSOR_TYPE_PICK_UP_GESTURE }; /** diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index f18cb7d22d14..6cb6a24f387c 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1810,33 +1810,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.sensor.orientation", int.class); /** - * <p>Noise model coefficients for each CFA mosaic channel.</p> - * <p>This tag contains two noise model coefficients for each CFA channel - * corresponding to the sensor amplification (S) and sensor readout - * noise (O). These are given as pairs of coefficients for each channel - * in the same order as channels listed for the CFA layout tag - * (see {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}). This is - * represented as an array of Pair<Double, Double>, where - * the first member of the Pair at index n is the S coefficient and the - * second member is the O coefficient for the nth color channel in the CFA.</p> - * <p>These coefficients are used in a two parameter noise model to describe - * the amount of noise present in the image for each CFA channel. The - * noise model used here is:</p> - * <p>N(x) = sqrt(Sx + O)</p> - * <p>Where x represents the recorded signal of a CFA channel normalized to - * the range [0, 1], and S and O are the noise model coeffiecients for - * that channel.</p> - * <p>A more detailed description of the noise model can be found in the - * Adobe DNG specification for the NoiseProfile tag.</p> - * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> - * - * @see CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT - */ - @PublicKey - public static final Key<android.util.Pair<Double,Double>[]> SENSOR_NOISE_PROFILE = - new Key<android.util.Pair<Double,Double>[]>("android.sensor.noiseProfile", new TypeReference<android.util.Pair<Double,Double>[]>() {{ }}); - - /** * <p>Lists the supported sensor test pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p> * <p>Optional. Defaults to [OFF].</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 9a3d80675aa4..a4a1559e4603 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -23,7 +23,7 @@ import android.hardware.CameraInfo; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.legacy.CameraDeviceUserShim; import android.hardware.camera2.legacy.LegacyMetadataMapper; -import android.hardware.camera2.utils.CameraBinderDecorator; +import android.hardware.camera2.utils.CameraServiceBinderDecorator; import android.hardware.camera2.utils.CameraRuntimeException; import android.hardware.camera2.utils.BinderHolder; import android.os.IBinder; @@ -52,6 +52,7 @@ import java.util.ArrayList; public final class CameraManager { private static final String TAG = "CameraManager"; + private final boolean DEBUG; /** * This should match the ICameraService definition @@ -63,7 +64,9 @@ public final class CameraManager { private static final int API_VERSION_1 = 1; private static final int API_VERSION_2 = 2; - private final ICameraService mCameraService; + // Access only through getCameraServiceLocked to deal with binder death + private ICameraService mCameraService; + private ArrayList<String> mDeviceIdList; private final ArrayMap<AvailabilityListener, Handler> mListenerMap = @@ -72,35 +75,17 @@ public final class CameraManager { private final Context mContext; private final Object mLock = new Object(); + private final CameraServiceListener mServiceListener = new CameraServiceListener(); + /** * @hide */ public CameraManager(Context context) { - mContext = context; - - IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME); - ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); - - /** - * Wrap the camera service in a decorator which automatically translates return codes - * into exceptions, and RemoteExceptions into other exceptions. - */ - mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw); - - try { - CameraBinderDecorator.throwOnError( - CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor()); - } catch (CameraRuntimeException e) { - handleRecoverableSetupErrors(e, "Failed to set up vendor tags"); - } + DEBUG = Log.isLoggable(TAG, Log.DEBUG); + synchronized(mLock) { + mContext = context; - try { - mCameraService.addListener(new CameraServiceListener()); - } catch(CameraRuntimeException e) { - throw new IllegalStateException("Failed to register a camera service listener", - e.asChecked()); - } catch (RemoteException e) { - // impossible + connectCameraServiceLocked(); } } @@ -116,13 +101,9 @@ public final class CameraManager { */ public String[] getCameraIdList() throws CameraAccessException { synchronized (mLock) { - try { - return getOrCreateDeviceIdListLocked().toArray(new String[0]); - } catch(CameraAccessException e) { - // this should almost never happen, except if mediaserver crashes - throw new IllegalStateException( - "Failed to query camera service for device ID list", e); - } + // ID list creation handles various known failures in device enumeration, so only + // exceptions it'll throw are unexpected, and should be propagated upward. + return getOrCreateDeviceIdListLocked().toArray(new String[0]); } } @@ -132,6 +113,9 @@ public final class CameraManager { * <p>Registering the same listener again will replace the handler with the * new one provided.</p> * + * <p>The first time a listener is registered, it is immediately called + * with the availability status of all currently known camera devices.</p> + * * @param listener The new listener to send camera availability notices to * @param handler The handler on which the listener should be invoked, or * {@code null} to use the current thread's {@link android.os.Looper looper}. @@ -147,10 +131,11 @@ public final class CameraManager { } synchronized (mLock) { - mListenerMap.put(listener, handler); - - // TODO: fire the current oldest known state when adding a new listener - // (must be done while holding lock) + Handler oldHandler = mListenerMap.put(listener, handler); + // For new listeners, provide initial availability information + if (oldHandler == null) { + mServiceListener.updateListenerLocked(listener, handler); + } } } @@ -176,64 +161,67 @@ public final class CameraManager { * @return The properties of the given camera * * @throws IllegalArgumentException if the cameraId does not match any - * currently connected camera device. - * @throws CameraAccessException if the camera is disabled by device policy. + * known camera device. + * @throws CameraAccessException if the camera is disabled by device policy, or + * the camera device has been disconnected. * @throws SecurityException if the application does not have permission to - * access the camera + * access the camera * * @see #getCameraIdList * @see android.app.admin.DevicePolicyManager#setCameraDisabled */ public CameraCharacteristics getCameraCharacteristics(String cameraId) throws CameraAccessException { + CameraCharacteristics characteristics = null; synchronized (mLock) { if (!getOrCreateDeviceIdListLocked().contains(cameraId)) { throw new IllegalArgumentException(String.format("Camera id %s does not match any" + " currently connected camera device", cameraId)); } - } - int id = Integer.valueOf(cameraId); + int id = Integer.valueOf(cameraId); - /* - * Get the camera characteristics from the camera service directly if it supports it, - * otherwise get them from the legacy shim instead. - */ + /* + * Get the camera characteristics from the camera service directly if it supports it, + * otherwise get them from the legacy shim instead. + */ - if (!supportsCamera2Api(cameraId)) { - // Legacy backwards compatibility path; build static info from the camera parameters - String[] outParameters = new String[1]; + ICameraService cameraService = getCameraServiceLocked(); + if (cameraService == null) { + throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable"); + } try { - mCameraService.getLegacyParameters(id, /*out*/outParameters); - String parameters = outParameters[0]; + if (!supportsCamera2ApiLocked(cameraId)) { + // Legacy backwards compatibility path; build static info from the camera + // parameters + String[] outParameters = new String[1]; - CameraInfo info = new CameraInfo(); - mCameraService.getCameraInfo(id, /*out*/info); + cameraService.getLegacyParameters(id, /*out*/outParameters); + String parameters = outParameters[0]; - return LegacyMetadataMapper.createCharacteristics(parameters, info); - } catch (RemoteException e) { - // Impossible - return null; - } catch (CameraRuntimeException e) { - throw e.asChecked(); - } + CameraInfo info = new CameraInfo(); + cameraService.getCameraInfo(id, /*out*/info); - } else { - // Normal path: Get the camera characteristics directly from the camera service - CameraMetadataNative info = new CameraMetadataNative(); + characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info); + } else { + // Normal path: Get the camera characteristics directly from the camera service + CameraMetadataNative info = new CameraMetadataNative(); - try { - mCameraService.getCameraCharacteristics(id, info); - } catch(CameraRuntimeException e) { + cameraService.getCameraCharacteristics(id, info); + + characteristics = new CameraCharacteristics(info); + } + } catch (CameraRuntimeException e) { throw e.asChecked(); - } catch(RemoteException e) { - // impossible - return null; + } catch (RemoteException e) { + // Camera service died - act as if the camera was disconnected + throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable", e); } - - return new CameraCharacteristics(info); } + return characteristics; } /** @@ -278,10 +266,16 @@ public final class CameraManager { ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); int id = Integer.parseInt(cameraId); try { - if (supportsCamera2Api(cameraId)) { + if (supportsCamera2ApiLocked(cameraId)) { // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices - mCameraService.connectDevice(callbacks, id, mContext.getPackageName(), - USE_CALLING_UID, holder); + ICameraService cameraService = getCameraServiceLocked(); + if (cameraService == null) { + throw new CameraRuntimeException( + CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable"); + } + cameraService.connectDevice(callbacks, id, + mContext.getPackageName(), USE_CALLING_UID, holder); cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder()); } else { // Use legacy camera implementation for HAL1 devices @@ -304,12 +298,19 @@ public final class CameraManager { if (e.getReason() == CameraAccessException.CAMERA_DISABLED || e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) { // Per API docs, these failures call onError and throw - throw e; + throw e.asChecked(); } } else { // Unexpected failure - rethrow throw e; } + } catch (RemoteException e) { + // Camera service died - act as if it's a CAMERA_DISCONNECTED case + CameraRuntimeException ce = new CameraRuntimeException( + CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable", e); + deviceImpl.setRemoteFailure(ce); + throw ce.asChecked(); } // TODO: factor out listener to be non-nested, then move setter to constructor @@ -324,8 +325,6 @@ public final class CameraManager { + cameraId); } catch (CameraRuntimeException e) { throw e.asChecked(); - } catch (RemoteException e) { - // impossible } return device; } @@ -444,27 +443,38 @@ public final class CameraManager { } } + /** + * Return or create the list of currently connected camera devices. + * + * <p>In case of errors connecting to the camera service, will return an empty list.</p> + */ private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException { if (mDeviceIdList == null) { int numCameras = 0; + ICameraService cameraService = getCameraServiceLocked(); + ArrayList<String> deviceIdList = new ArrayList<>(); + + // If no camera service, then no devices + if (cameraService == null) { + return deviceIdList; + } try { - numCameras = mCameraService.getNumberOfCameras(); + numCameras = cameraService.getNumberOfCameras(); } catch(CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { - // impossible - return null; + // camera service just died - if no camera service, then no devices + return deviceIdList; } - mDeviceIdList = new ArrayList<String>(); CameraMetadataNative info = new CameraMetadataNative(); for (int i = 0; i < numCameras; ++i) { // Non-removable cameras use integers starting at 0 for their // identifiers boolean isDeviceSupported = false; try { - mCameraService.getCameraCharacteristics(i, info); + cameraService.getCameraCharacteristics(i, info); if (!info.isEmpty()) { isDeviceSupported = true; } else { @@ -474,16 +484,26 @@ public final class CameraManager { // Got a BAD_VALUE from service, meaning that this // device is not supported. } catch(CameraRuntimeException e) { - throw e.asChecked(); + // DISCONNECTED means that the HAL reported an low-level error getting the + // device info; skip listing the device. Other errors, + // propagate exception onward + if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) { + throw e.asChecked(); + } } catch(RemoteException e) { - // impossible + // Camera service died - no devices to list + deviceIdList.clear(); + return deviceIdList; } if (isDeviceSupported) { - mDeviceIdList.add(String.valueOf(i)); + deviceIdList.add(String.valueOf(i)); + } else { + Log.w(TAG, "Error querying camera device " + i + " for listing."); } - } + } + mDeviceIdList = deviceIdList; } return mDeviceIdList; } @@ -506,8 +526,8 @@ public final class CameraManager { * @param cameraId a non-{@code null} camera identifier * @return {@code false} if the legacy shim needs to be used, {@code true} otherwise. */ - private boolean supportsCamera2Api(String cameraId) { - return supportsCameraApi(cameraId, API_VERSION_2); + private boolean supportsCamera2ApiLocked(String cameraId) { + return supportsCameraApiLocked(cameraId, API_VERSION_2); } /** @@ -517,33 +537,125 @@ public final class CameraManager { * @param apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2} * @return {@code true} if connecting will work for that device version. */ - private boolean supportsCameraApi(String cameraId, int apiVersion) { + private boolean supportsCameraApiLocked(String cameraId, int apiVersion) { int id = Integer.parseInt(cameraId); /* * Possible return values: - * - NO_ERROR => Camera2 API is supported - * - CAMERA_DEPRECATED_HAL => Camera2 API is *not* supported (thrown as an exception) + * - NO_ERROR => CameraX API is supported + * - CAMERA_DEPRECATED_HAL => CameraX API is *not* supported (thrown as an exception) + * - Remote exception => If the camera service died * * Anything else is an unexpected error we don't want to recover from. */ - try { - int res = mCameraService.supportsCameraApi(id, apiVersion); + ICameraService cameraService = getCameraServiceLocked(); + // If no camera service, no support + if (cameraService == null) return false; + + int res = cameraService.supportsCameraApi(id, apiVersion); - if (res != CameraBinderDecorator.NO_ERROR) { + if (res != CameraServiceBinderDecorator.NO_ERROR) { throw new AssertionError("Unexpected value " + res); } - return true; } catch (CameraRuntimeException e) { - if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) { - return false; - } else { + if (e.getReason() != CameraAccessException.CAMERA_DEPRECATED_HAL) { throw e; } + // API level is not supported } catch (RemoteException e) { - throw new AssertionError("Camera service unreachable", e); + // Camera service is now down, no support for any API level + } + return false; + } + + /** + * Connect to the camera service if it's available, and set up listeners. + * + * <p>Sets mCameraService to a valid pointer or null if the connection does not succeed.</p> + */ + private void connectCameraServiceLocked() { + mCameraService = null; + IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME); + if (cameraServiceBinder == null) { + // Camera service is now down, leave mCameraService as null + return; + } + try { + cameraServiceBinder.linkToDeath(new CameraServiceDeathListener(), /*flags*/ 0); + } catch (RemoteException e) { + // Camera service is now down, leave mCameraService as null + return; + } + + ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); + + /** + * Wrap the camera service in a decorator which automatically translates return codes + * into exceptions. + */ + ICameraService cameraService = CameraServiceBinderDecorator.newInstance(cameraServiceRaw); + + try { + CameraServiceBinderDecorator.throwOnError( + CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor()); + } catch (CameraRuntimeException e) { + handleRecoverableSetupErrors(e, "Failed to set up vendor tags"); + } + + try { + cameraService.addListener(mServiceListener); + mCameraService = cameraService; + } catch(CameraRuntimeException e) { + // Unexpected failure + throw new IllegalStateException("Failed to register a camera service listener", + e.asChecked()); + } catch (RemoteException e) { + // Camera service is now down, leave mCameraService as null + } + } + + /** + * Return a best-effort ICameraService. + * + * <p>This will be null if the camera service + * is not currently available. If the camera service has died since the last + * use of the camera service, will try to reconnect to the service.</p> + */ + private ICameraService getCameraServiceLocked() { + if (mCameraService == null) { + Log.i(TAG, "getCameraServiceLocked: Reconnecting to camera service"); + connectCameraServiceLocked(); + if (mCameraService == null) { + Log.e(TAG, "Camera service is unavailable"); + } + } + return mCameraService; + } + + /** + * Listener for camera service death. + * + * <p>The camera service isn't supposed to die under any normal circumstances, but can be turned + * off during debug, or crash due to bugs. So detect that and null out the interface object, so + * that the next calls to the manager can try to reconnect.</p> + */ + private class CameraServiceDeathListener implements IBinder.DeathRecipient { + public void binderDied() { + synchronized(mLock) { + mCameraService = null; + // Tell listeners that the cameras are _available_, because any existing clients + // will have gotten disconnected. This is optimistic under the assumption that the + // service will be back shortly. + // + // Without this, a camera service crash while a camera is open will never signal to + // listeners that previously in-use cameras are now available. + for (String cameraId : mDeviceIdList) { + mServiceListener.onStatusChangedLocked(CameraServiceListener.STATUS_PRESENT, + cameraId); + } + } } } @@ -595,77 +707,102 @@ public final class CameraManager { } } + private void postSingleUpdate(final AvailabilityListener listener, final Handler handler, + final String id, final int status) { + if (isAvailable(status)) { + handler.post( + new Runnable() { + @Override + public void run() { + listener.onCameraAvailable(id); + } + }); + } else { + handler.post( + new Runnable() { + @Override + public void run() { + listener.onCameraUnavailable(id); + } + }); + } + } + + /** + * Send the state of all known cameras to the provided listener, to initialize + * the listener's knowledge of camera state. + */ + public void updateListenerLocked(AvailabilityListener listener, Handler handler) { + for (int i = 0; i < mDeviceStatus.size(); i++) { + String id = mDeviceStatus.keyAt(i); + Integer status = mDeviceStatus.valueAt(i); + postSingleUpdate(listener, handler, id, status); + } + } + @Override public void onStatusChanged(int status, int cameraId) throws RemoteException { synchronized(CameraManager.this.mLock) { + onStatusChangedLocked(status, String.valueOf(cameraId)); + } + } + public void onStatusChangedLocked(int status, String id) { + if (DEBUG) { Log.v(TAG, - String.format("Camera id %d has status changed to 0x%x", cameraId, status)); - - final String id = String.valueOf(cameraId); + String.format("Camera id %s has status changed to 0x%x", id, status)); + } - if (!validStatus(status)) { - Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId, - status)); - return; - } + if (!validStatus(status)) { + Log.e(TAG, String.format("Ignoring invalid device %s status 0x%x", id, + status)); + return; + } - Integer oldStatus = mDeviceStatus.put(id, status); + Integer oldStatus = mDeviceStatus.put(id, status); - if (oldStatus != null && oldStatus == status) { + if (oldStatus != null && oldStatus == status) { + if (DEBUG) { Log.v(TAG, String.format( - "Device status changed to 0x%x, which is what it already was", - status)); - return; + "Device status changed to 0x%x, which is what it already was", + status)); } + return; + } - // TODO: consider abstracting out this state minimization + transition - // into a separate - // more easily testable class - // i.e. (new State()).addState(STATE_AVAILABLE) - // .addState(STATE_NOT_AVAILABLE) - // .addTransition(STATUS_PRESENT, STATE_AVAILABLE), - // .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE) - // .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE); - // .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE); - - // Translate all the statuses to either 'available' or 'not available' - // available -> available => no new update - // not available -> not available => no new update - if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) { - + // TODO: consider abstracting out this state minimization + transition + // into a separate + // more easily testable class + // i.e. (new State()).addState(STATE_AVAILABLE) + // .addState(STATE_NOT_AVAILABLE) + // .addTransition(STATUS_PRESENT, STATE_AVAILABLE), + // .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE) + // .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE); + // .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE); + + // Translate all the statuses to either 'available' or 'not available' + // available -> available => no new update + // not available -> not available => no new update + if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) { + if (DEBUG) { Log.v(TAG, String.format( - "Device status was previously available (%d), " + - " and is now again available (%d)" + - "so no new client visible update will be sent", - isAvailable(status), isAvailable(status))); - return; + "Device status was previously available (%d), " + + " and is now again available (%d)" + + "so no new client visible update will be sent", + isAvailable(status), isAvailable(status))); } + return; + } + + final int listenerCount = mListenerMap.size(); + for (int i = 0; i < listenerCount; i++) { + Handler handler = mListenerMap.valueAt(i); + final AvailabilityListener listener = mListenerMap.keyAt(i); + + postSingleUpdate(listener, handler, id, status); + } + } // onStatusChangedLocked - final int listenerCount = mListenerMap.size(); - for (int i = 0; i < listenerCount; i++) { - Handler handler = mListenerMap.valueAt(i); - final AvailabilityListener listener = mListenerMap.keyAt(i); - if (isAvailable(status)) { - handler.post( - new Runnable() { - @Override - public void run() { - listener.onCameraAvailable(id); - } - }); - } else { - handler.post( - new Runnable() { - @Override - public void run() { - listener.onCameraUnavailable(id); - } - }); - } - } // for - } // synchronized - } // onStatusChanged } // CameraServiceListener } // CameraManager diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index c9774ed1c6de..20a04f01a638 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2242,6 +2242,33 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class); /** + * <p>Noise model coefficients for each CFA mosaic channel.</p> + * <p>This tag contains two noise model coefficients for each CFA channel + * corresponding to the sensor amplification (S) and sensor readout + * noise (O). These are given as pairs of coefficients for each channel + * in the same order as channels listed for the CFA layout tag + * (see {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}). This is + * represented as an array of Pair<Double, Double>, where + * the first member of the Pair at index n is the S coefficient and the + * second member is the O coefficient for the nth color channel in the CFA.</p> + * <p>These coefficients are used in a two parameter noise model to describe + * the amount of noise present in the image for each CFA channel. The + * noise model used here is:</p> + * <p>N(x) = sqrt(Sx + O)</p> + * <p>Where x represents the recorded signal of a CFA channel normalized to + * the range [0, 1], and S and O are the noise model coeffiecients for + * that channel.</p> + * <p>A more detailed description of the noise model can be found in the + * Adobe DNG specification for the NoiseProfile tag.</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * + * @see CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT + */ + @PublicKey + public static final Key<android.util.Pair<Double,Double>[]> SENSOR_NOISE_PROFILE = + new Key<android.util.Pair<Double,Double>[]>("android.sensor.noiseProfile", new TypeReference<android.util.Pair<Double,Double>[]>() {{ }}); + + /** * <p>The worst-case divergence between Bayer green channels.</p> * <p>This value is an estimate of the worst case split between the * Bayer green channels in the red and blue rows in the sensor color diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index fb1bc1551372..ed4e457859aa 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -294,8 +294,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice { final int code = failureCode; final boolean isError = failureIsError; synchronized(mInterfaceLock) { - if (mRemoteDevice == null) return; // Camera already closed, can't go to error state - mInError = true; mDeviceHandler.post(new Runnable() { @Override diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java index ab7e8449230c..2fa9d8520b8d 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java @@ -65,7 +65,7 @@ public class CameraDeviceState { void onError(int errorCode, RequestHolder holder); void onConfiguring(); void onIdle(); - void onCaptureStarted(RequestHolder holder); + void onCaptureStarted(RequestHolder holder, long timestamp); void onCaptureResult(CameraMetadataNative result, RequestHolder holder); } @@ -125,11 +125,12 @@ public class CameraDeviceState { * </p> * * @param request A {@link RequestHolder} containing the request for the current capture. + * @param timestamp The timestamp of the capture start in nanoseconds. * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. */ - public synchronized int setCaptureStart(final RequestHolder request) { + public synchronized int setCaptureStart(final RequestHolder request, long timestamp) { mCurrentRequest = request; - doStateTransition(STATE_CAPTURING); + doStateTransition(STATE_CAPTURING, timestamp); return mCurrentError; } @@ -180,6 +181,10 @@ public class CameraDeviceState { } private void doStateTransition(int newState) { + doStateTransition(newState, /*timestamp*/0); + } + + private void doStateTransition(int newState, final long timestamp) { if (DEBUG) { if (newState != mCurrentState) { Log.d(TAG, "Transitioning to state " + newState); @@ -250,7 +255,7 @@ public class CameraDeviceState { mCurrentHandler.post(new Runnable() { @Override public void run() { - mCurrentListener.onCaptureStarted(mCurrentRequest); + mCurrentListener.onCaptureStarted(mCurrentRequest, timestamp); } }); } diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java new file mode 100644 index 000000000000..ab31d8ca9ae8 --- /dev/null +++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java @@ -0,0 +1,453 @@ +/* + * 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 android.hardware.camera2.legacy; + +import android.hardware.camera2.impl.CameraMetadataNative; +import android.util.Log; +import android.util.Pair; + +import java.util.ArrayDeque; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Collect timestamps and state for each {@link CaptureRequest} as it passes through + * the Legacy camera pipeline. + */ +public class CaptureCollector { + private static final String TAG = "CaptureCollector"; + + private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); + + private static final int FLAG_RECEIVED_JPEG = 1; + private static final int FLAG_RECEIVED_JPEG_TS = 2; + private static final int FLAG_RECEIVED_PREVIEW = 4; + private static final int FLAG_RECEIVED_PREVIEW_TS = 8; + private static final int FLAG_RECEIVED_ALL_JPEG = FLAG_RECEIVED_JPEG | FLAG_RECEIVED_JPEG_TS; + private static final int FLAG_RECEIVED_ALL_PREVIEW = FLAG_RECEIVED_PREVIEW | + FLAG_RECEIVED_PREVIEW_TS; + + private static final int MAX_JPEGS_IN_FLIGHT = 1; + + private class CaptureHolder { + private final RequestHolder mRequest; + private final LegacyRequest mLegacy; + public final boolean needsJpeg; + public final boolean needsPreview; + + private long mTimestamp = 0; + private int mReceivedFlags = 0; + private boolean mHasStarted = false; + + public CaptureHolder(RequestHolder request, LegacyRequest legacyHolder) { + mRequest = request; + mLegacy = legacyHolder; + needsJpeg = request.hasJpegTargets(); + needsPreview = request.hasPreviewTargets(); + } + + public boolean isPreviewCompleted() { + return (mReceivedFlags & FLAG_RECEIVED_ALL_PREVIEW) == FLAG_RECEIVED_ALL_PREVIEW; + } + + public boolean isJpegCompleted() { + return (mReceivedFlags & FLAG_RECEIVED_ALL_JPEG) == FLAG_RECEIVED_ALL_JPEG; + } + + public boolean isCompleted() { + return (needsJpeg == isJpegCompleted()) && (needsPreview == isPreviewCompleted()); + } + + public void tryComplete() { + if (isCompleted()) { + if (needsPreview && isPreviewCompleted()) { + CaptureCollector.this.onPreviewCompleted(); + } + CaptureCollector.this.onRequestCompleted(mRequest, mLegacy, mTimestamp); + } + } + + public void setJpegTimestamp(long timestamp) { + if (DEBUG) { + Log.d(TAG, "setJpegTimestamp - called for request " + mRequest.getRequestId()); + } + if (!needsJpeg) { + throw new IllegalStateException( + "setJpegTimestamp called for capture with no jpeg targets."); + } + if (isCompleted()) { + throw new IllegalStateException( + "setJpegTimestamp called on already completed request."); + } + + mReceivedFlags |= FLAG_RECEIVED_JPEG_TS; + + if (mTimestamp == 0) { + mTimestamp = timestamp; + } + + if (!mHasStarted) { + mHasStarted = true; + CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp); + } + + tryComplete(); + } + + public void setJpegProduced() { + if (DEBUG) { + Log.d(TAG, "setJpegProduced - called for request " + mRequest.getRequestId()); + } + if (!needsJpeg) { + throw new IllegalStateException( + "setJpegProduced called for capture with no jpeg targets."); + } + if (isCompleted()) { + throw new IllegalStateException( + "setJpegProduced called on already completed request."); + } + + mReceivedFlags |= FLAG_RECEIVED_JPEG; + tryComplete(); + } + + public void setPreviewTimestamp(long timestamp) { + if (DEBUG) { + Log.d(TAG, "setPreviewTimestamp - called for request " + mRequest.getRequestId()); + } + if (!needsPreview) { + throw new IllegalStateException( + "setPreviewTimestamp called for capture with no preview targets."); + } + if (isCompleted()) { + throw new IllegalStateException( + "setPreviewTimestamp called on already completed request."); + } + + mReceivedFlags |= FLAG_RECEIVED_PREVIEW_TS; + + if (mTimestamp == 0) { + mTimestamp = timestamp; + } + + if (!needsJpeg) { + if (!mHasStarted) { + mHasStarted = true; + CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp); + } + } + + tryComplete(); + } + + public void setPreviewProduced() { + if (DEBUG) { + Log.d(TAG, "setPreviewProduced - called for request " + mRequest.getRequestId()); + } + if (!needsPreview) { + throw new IllegalStateException( + "setPreviewProduced called for capture with no preview targets."); + } + if (isCompleted()) { + throw new IllegalStateException( + "setPreviewProduced called on already completed request."); + } + + mReceivedFlags |= FLAG_RECEIVED_PREVIEW; + tryComplete(); + } + } + + private final ArrayDeque<CaptureHolder> mJpegCaptureQueue; + private final ArrayDeque<CaptureHolder> mJpegProduceQueue; + private final ArrayDeque<CaptureHolder> mPreviewCaptureQueue; + private final ArrayDeque<CaptureHolder> mPreviewProduceQueue; + + private final ReentrantLock mLock = new ReentrantLock(); + private final Condition mIsEmpty; + private final Condition mPreviewsEmpty; + private final Condition mNotFull; + private final CameraDeviceState mDeviceState; + private final LegacyResultMapper mMapper = new LegacyResultMapper(); + private int mInFlight = 0; + private int mInFlightPreviews = 0; + private final int mMaxInFlight; + + /** + * Create a new {@link CaptureCollector} that can modify the given {@link CameraDeviceState}. + * + * @param maxInFlight max allowed in-flight requests. + * @param deviceState the {@link CameraDeviceState} to update as requests are processed. + */ + public CaptureCollector(int maxInFlight, CameraDeviceState deviceState) { + mMaxInFlight = maxInFlight; + mJpegCaptureQueue = new ArrayDeque<>(MAX_JPEGS_IN_FLIGHT); + mJpegProduceQueue = new ArrayDeque<>(MAX_JPEGS_IN_FLIGHT); + mPreviewCaptureQueue = new ArrayDeque<>(mMaxInFlight); + mPreviewProduceQueue = new ArrayDeque<>(mMaxInFlight); + mIsEmpty = mLock.newCondition(); + mNotFull = mLock.newCondition(); + mPreviewsEmpty = mLock.newCondition(); + mDeviceState = deviceState; + } + + /** + * Queue a new request. + * + * <p> + * For requests that use the Camera1 API preview output stream, this will block if there are + * already {@code maxInFlight} requests in progress (until at least one prior request has + * completed). For requests that use the Camera1 API jpeg callbacks, this will block until + * all prior requests have been completed to avoid stopping preview for + * {@link android.hardware.Camera#takePicture} before prior preview requests have been + * completed. + * </p> + * @param holder the {@link RequestHolder} for this request. + * @param legacy the {@link LegacyRequest} for this request; this will not be mutated. + * @param timeout a timeout to use for this call. + * @param unit the units to use for the timeout. + * @return {@code false} if this method timed out. + * @throws InterruptedException if this thread is interrupted. + */ + public boolean queueRequest(RequestHolder holder, LegacyRequest legacy, long timeout, + TimeUnit unit) + throws InterruptedException { + CaptureHolder h = new CaptureHolder(holder, legacy); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.mLock; + lock.lock(); + try { + if (DEBUG) { + Log.d(TAG, "queueRequest for request " + holder.getRequestId() + + " - " + mInFlight + " requests remain in flight."); + } + if (h.needsJpeg) { + // Wait for all current requests to finish before queueing jpeg. + while (mInFlight > 0) { + if (nanos <= 0) { + return false; + } + nanos = mIsEmpty.awaitNanos(nanos); + } + mJpegCaptureQueue.add(h); + mJpegProduceQueue.add(h); + } + if (h.needsPreview) { + while (mInFlight >= mMaxInFlight) { + if (nanos <= 0) { + return false; + } + nanos = mNotFull.awaitNanos(nanos); + } + mPreviewCaptureQueue.add(h); + mPreviewProduceQueue.add(h); + mInFlightPreviews++; + } + + if (!(h.needsJpeg || h.needsPreview)) { + throw new IllegalStateException("Request must target at least one output surface!"); + } + + mInFlight++; + return true; + } finally { + lock.unlock(); + } + } + + /** + * Wait all queued requests to complete. + * + * @param timeout a timeout to use for this call. + * @param unit the units to use for the timeout. + * @return {@code false} if this method timed out. + * @throws InterruptedException if this thread is interrupted. + */ + public boolean waitForEmpty(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.mLock; + lock.lock(); + try { + while (mInFlight > 0) { + if (nanos <= 0) { + return false; + } + nanos = mIsEmpty.awaitNanos(nanos); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * Wait all queued requests that use the Camera1 API preview output to complete. + * + * @param timeout a timeout to use for this call. + * @param unit the units to use for the timeout. + * @return {@code false} if this method timed out. + * @throws InterruptedException if this thread is interrupted. + */ + public boolean waitForPreviewsEmpty(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.mLock; + lock.lock(); + try { + while (mInFlightPreviews > 0) { + if (nanos <= 0) { + return false; + } + nanos = mPreviewsEmpty.awaitNanos(nanos); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * Called to alert the {@link CaptureCollector} that the jpeg capture has begun. + * + * @param timestamp the time of the jpeg capture. + * @return the {@link RequestHolder} for the request associated with this capture. + */ + public RequestHolder jpegCaptured(long timestamp) { + final ReentrantLock lock = this.mLock; + lock.lock(); + try { + CaptureHolder h = mJpegCaptureQueue.poll(); + if (h == null) { + Log.w(TAG, "jpegCaptured called with no jpeg request on queue!"); + return null; + } + h.setJpegTimestamp(timestamp); + return h.mRequest; + } finally { + lock.unlock(); + } + } + + /** + * Called to alert the {@link CaptureCollector} that the jpeg capture has completed. + * + * @return a pair containing the {@link RequestHolder} and the timestamp of the capture. + */ + public Pair<RequestHolder, Long> jpegProduced() { + final ReentrantLock lock = this.mLock; + lock.lock(); + try { + CaptureHolder h = mJpegProduceQueue.poll(); + if (h == null) { + Log.w(TAG, "jpegProduced called with no jpeg request on queue!"); + return null; + } + h.setJpegProduced(); + return new Pair<>(h.mRequest, h.mTimestamp); + } finally { + lock.unlock(); + } + } + + /** + * Check if there are any pending capture requests that use the Camera1 API preview output. + * + * @return {@code true} if there are pending preview requests. + */ + public boolean hasPendingPreviewCaptures() { + final ReentrantLock lock = this.mLock; + lock.lock(); + try { + return !mPreviewCaptureQueue.isEmpty(); + } finally { + lock.unlock(); + } + } + + /** + * Called to alert the {@link CaptureCollector} that the preview capture has begun. + * + * @param timestamp the time of the preview capture. + * @return a pair containing the {@link RequestHolder} and the timestamp of the capture. + */ + public Pair<RequestHolder, Long> previewCaptured(long timestamp) { + final ReentrantLock lock = this.mLock; + lock.lock(); + try { + CaptureHolder h = mPreviewCaptureQueue.poll(); + if (h == null) { + Log.w(TAG, "previewCaptured called with no preview request on queue!"); + return null; + } + h.setPreviewTimestamp(timestamp); + return new Pair<>(h.mRequest, h.mTimestamp); + } finally { + lock.unlock(); + } + } + + /** + * Called to alert the {@link CaptureCollector} that the preview capture has completed. + * + * @return the {@link RequestHolder} for the request associated with this capture. + */ + public RequestHolder previewProduced() { + final ReentrantLock lock = this.mLock; + lock.lock(); + try { + CaptureHolder h = mPreviewProduceQueue.poll(); + if (h == null) { + Log.w(TAG, "previewProduced called with no preview request on queue!"); + return null; + } + h.setPreviewProduced(); + return h.mRequest; + } finally { + lock.unlock(); + } + } + + private void onPreviewCompleted() { + mInFlightPreviews--; + if (mInFlightPreviews < 0) { + throw new IllegalStateException( + "More preview captures completed than requests queued."); + } + if (mInFlightPreviews == 0) { + mPreviewsEmpty.signalAll(); + } + } + + private void onRequestCompleted(RequestHolder request, LegacyRequest legacyHolder, + long timestamp) { + mInFlight--; + if (DEBUG) { + Log.d(TAG, "Completed request " + request.getRequestId() + + ", " + mInFlight + " requests remain in flight."); + } + if (mInFlight < 0) { + throw new IllegalStateException( + "More captures completed than requests queued."); + } + mNotFull.signalAll(); + if (mInFlight == 0) { + mIsEmpty.signalAll(); + } + CameraMetadataNative result = mMapper.cachedConvertResultMetadata( + legacyHolder, timestamp); + mDeviceState.setCaptureResult(request, result); + } +} diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java index 5d44fd28609d..06521cf16f59 100644 --- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java @@ -25,6 +25,8 @@ import android.view.Surface; import java.util.Collection; +import static com.android.internal.util.Preconditions.*; + /** * GLThreadManager handles the thread used for rendering into the configured output surfaces. */ @@ -38,6 +40,8 @@ public class GLThreadManager { private static final int MSG_DROP_FRAMES = 4; private static final int MSG_ALLOW_FRAMES = 5; + private CaptureCollector mCaptureCollector; + private final SurfaceTextureRenderer mTextureRenderer; private final RequestHandlerThread mGLHandlerThread; @@ -51,10 +55,13 @@ public class GLThreadManager { private static class ConfigureHolder { public final ConditionVariable condition; public final Collection<Surface> surfaces; + public final CaptureCollector collector; - public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces) { + public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces, + CaptureCollector collector) { this.condition = condition; this.surfaces = surfaces; + this.collector = collector; } } @@ -74,6 +81,7 @@ public class GLThreadManager { ConfigureHolder configure = (ConfigureHolder) msg.obj; mTextureRenderer.cleanupEGLContext(); mTextureRenderer.configureSurfaces(configure.surfaces); + mCaptureCollector = checkNotNull(configure.collector); configure.condition.open(); mConfigured = true; break; @@ -88,7 +96,7 @@ public class GLThreadManager { if (!mConfigured) { Log.e(TAG, "Dropping frame, EGL context not configured!"); } - mTextureRenderer.drawIntoSurfaces((Collection<Surface>) msg.obj); + mTextureRenderer.drawIntoSurfaces(mCaptureCollector); break; case MSG_CLEANUP: mTextureRenderer.cleanupEGLContext(); @@ -158,16 +166,11 @@ public class GLThreadManager { } /** - * Queue a new call to draw into a given set of surfaces. - * - * <p> - * The set of surfaces passed here must be a subset of the set of surfaces passed in - * the last call to {@link #setConfigurationAndWait}. - * </p> - * - * @param targets a collection of {@link android.view.Surface}s to draw into. + * Queue a new call to draw into the surfaces specified in the next available preview + * request from the {@link CaptureCollector} passed to + * {@link #setConfigurationAndWait(java.util.Collection, CaptureCollector)}; */ - public void queueNewFrame(Collection<Surface> targets) { + public void queueNewFrame() { Handler handler = mGLHandlerThread.getHandler(); /** @@ -175,7 +178,7 @@ public class GLThreadManager { * are produced, drop frames rather than allowing the queue to back up. */ if (!handler.hasMessages(MSG_NEW_FRAME)) { - handler.sendMessage(handler.obtainMessage(MSG_NEW_FRAME, targets)); + handler.sendMessage(handler.obtainMessage(MSG_NEW_FRAME)); } else { Log.e(TAG, "GLThread dropping frame. Not consuming frames quickly enough!"); } @@ -186,12 +189,14 @@ public class GLThreadManager { * this configuration has been applied. * * @param surfaces a collection of {@link android.view.Surface}s to configure. + * @param collector a {@link CaptureCollector} to retrieve requests from. */ - public void setConfigurationAndWait(Collection<Surface> surfaces) { + public void setConfigurationAndWait(Collection<Surface> surfaces, CaptureCollector collector) { + checkNotNull(collector, "collector must not be null"); Handler handler = mGLHandlerThread.getHandler(); final ConditionVariable condition = new ConditionVariable(/*closed*/false); - ConfigureHolder configure = new ConfigureHolder(condition, surfaces); + ConfigureHolder configure = new ConfigureHolder(condition, surfaces, collector); Message m = handler.obtainMessage(MSG_NEW_CONFIGURATION, /*arg1*/0, /*arg2*/0, configure); handler.sendMessage(m); diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index 71d3d4b20289..cbf4a3d1bb06 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -135,10 +135,9 @@ public class LegacyCameraDevice implements AutoCloseable { } @Override - public void onCaptureStarted(RequestHolder holder) { + public void onCaptureStarted(RequestHolder holder, final long timestamp) { final CaptureResultExtras extras = getExtrasFromRequest(holder); - final long timestamp = System.nanoTime(); mResultHandler.post(new Runnable() { @Override public void run() { @@ -146,7 +145,6 @@ public class LegacyCameraDevice implements AutoCloseable { Log.d(TAG, "doing onCaptureStarted callback."); } try { - // TODO: Don't fake timestamp mDeviceCallbacks.onCaptureStarted(extras, timestamp); } catch (RemoteException e) { throw new IllegalStateException( @@ -167,7 +165,6 @@ public class LegacyCameraDevice implements AutoCloseable { Log.d(TAG, "doing onCaptureResult callback."); } try { - // TODO: Don't fake metadata mDeviceCallbacks.onResultReceived(result, extras); } catch (RemoteException e) { throw new IllegalStateException( @@ -483,6 +480,12 @@ public class LegacyCameraDevice implements AutoCloseable { return new Size(dimens[0], dimens[1]); } + static void setNextTimestamp(Surface surface, long timestamp) + throws BufferQueueAbandonedException { + checkNotNull(surface); + LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp)); + } + private static native int nativeDetectSurfaceType(Surface surface); private static native int nativeDetectSurfaceDimens(Surface surface, @@ -506,4 +509,5 @@ public class LegacyCameraDevice implements AutoCloseable { private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture, /*out*/int[/*2*/] dimens); + private static native int nativeSetNextTimestamp(Surface surface, long timestamp); } diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index cc7a90eb8d19..066b416f05e2 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -38,6 +38,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; import static com.android.internal.util.Preconditions.*; @@ -62,22 +64,20 @@ public class RequestThreadManager { private final CameraCharacteristics mCharacteristics; private final CameraDeviceState mDeviceState; + private final CaptureCollector mCaptureCollector; private static final int MSG_CONFIGURE_OUTPUTS = 1; private static final int MSG_SUBMIT_CAPTURE_REQUEST = 2; private static final int MSG_CLEANUP = 3; + private static final int MAX_IN_FLIGHT_REQUESTS = 2; + private static final int PREVIEW_FRAME_TIMEOUT = 300; // ms private static final int JPEG_FRAME_TIMEOUT = 3000; // ms (same as CTS for API2) private static final float ASPECT_RATIO_TOLERANCE = 0.01f; private boolean mPreviewRunning = false; - private volatile long mLastJpegTimestamp; - private volatile long mLastPreviewTimestamp; - private volatile RequestHolder mInFlightPreview; - private volatile RequestHolder mInFlightJpeg; - private final List<Surface> mPreviewOutputs = new ArrayList<>(); private final List<Surface> mCallbackOutputs = new ArrayList<>(); private GLThreadManager mGLThreadManager; @@ -167,16 +167,16 @@ public class RequestThreadManager { } private final ConditionVariable mReceivedJpeg = new ConditionVariable(false); - private final ConditionVariable mReceivedPreview = new ConditionVariable(false); private final Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { Log.i(TAG, "Received jpeg."); - RequestHolder holder = mInFlightJpeg; + Pair<RequestHolder, Long> captureInfo = mCaptureCollector.jpegProduced(); + RequestHolder holder = captureInfo.first; + long timestamp = captureInfo.second; if (holder == null) { - Log.w(TAG, "Dropping jpeg frame."); - mInFlightJpeg = null; + Log.e(TAG, "Dropping jpeg frame."); return; } for (Surface s : holder.getHolderTargets()) { @@ -184,6 +184,7 @@ public class RequestThreadManager { if (RequestHolder.jpegType(s)) { Log.i(TAG, "Producing jpeg buffer..."); LegacyCameraDevice.setSurfaceDimens(s, data.length, /*height*/1); + LegacyCameraDevice.setNextTimestamp(s, timestamp); LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1, CameraMetadataNative.NATIVE_JPEG_FORMAT); } @@ -191,6 +192,7 @@ public class RequestThreadManager { Log.w(TAG, "Surface abandoned, dropping frame. ", e); } } + mReceivedJpeg.open(); } }; @@ -198,7 +200,7 @@ public class RequestThreadManager { private final Camera.ShutterCallback mJpegShutterCallback = new Camera.ShutterCallback() { @Override public void onShutter() { - mLastJpegTimestamp = SystemClock.elapsedRealtimeNanos(); + mCaptureCollector.jpegCaptured(SystemClock.elapsedRealtimeNanos()); } }; @@ -206,29 +208,10 @@ public class RequestThreadManager { new SurfaceTexture.OnFrameAvailableListener() { @Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { - RequestHolder holder = mInFlightPreview; - if (DEBUG) { mPrevCounter.countAndLog(); } - - if (holder == null) { - mGLThreadManager.queueNewFrame(null); - Log.w(TAG, "Dropping preview frame."); - return; - } - - mInFlightPreview = null; - - if (holder.hasPreviewTargets()) { - mGLThreadManager.queueNewFrame(holder.getHolderTargets()); - } - - /** - * TODO: Get timestamp from GL thread after buffer update. - */ - mLastPreviewTimestamp = surfaceTexture.getTimestamp(); - mReceivedPreview.open(); + mGLThreadManager.queueNewFrame(); } }; @@ -256,14 +239,11 @@ public class RequestThreadManager { mCamera.setPreviewTexture(mDummyTexture); startPreview(); } - mInFlightJpeg = request; - // TODO: Hook up shutter callback to CameraDeviceStateListener#onCaptureStarted mCamera.takePicture(mJpegShutterCallback, /*raw*/null, mJpegCallback); mPreviewRunning = false; } private void doPreviewCapture(RequestHolder request) throws IOException { - mInFlightPreview = request; if (mPreviewRunning) { return; // Already running } @@ -290,8 +270,6 @@ public class RequestThreadManager { mPreviewOutputs.clear(); mCallbackOutputs.clear(); mPreviewTexture = null; - mInFlightPreview = null; - mInFlightJpeg = null; int facing = mCharacteristics.get(CameraCharacteristics.LENS_FACING); int orientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); @@ -389,7 +367,7 @@ public class RequestThreadManager { mGLThreadManager.start(); } mGLThreadManager.waitUntilStarted(); - mGLThreadManager.setConfigurationAndWait(mPreviewOutputs); + mGLThreadManager.setConfigurationAndWait(mPreviewOutputs, mCaptureCollector); mGLThreadManager.allowNewFrames(); mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture(); if (mPreviewTexture != null) { @@ -553,6 +531,18 @@ public class RequestThreadManager { int sizes = config.surfaces != null ? config.surfaces.size() : 0; Log.i(TAG, "Configure outputs: " + sizes + " surfaces configured."); + + try { + boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT, + TimeUnit.MILLISECONDS); + if (!success) { + Log.e(TAG, "Timed out while queueing configure request."); + } + } catch (InterruptedException e) { + // TODO: report error to CameraDevice + Log.e(TAG, "Interrupted while waiting for requests to complete."); + } + try { configureOutputs(config.surfaces); } catch (IOException e) { @@ -571,6 +561,16 @@ public class RequestThreadManager { // Get the next burst from the request queue. Pair<BurstHolder, Long> nextBurst = mRequestQueue.getNext(); if (nextBurst == null) { + try { + boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT, + TimeUnit.MILLISECONDS); + if (!success) { + Log.e(TAG, "Timed out while waiting for empty."); + } + } catch (InterruptedException e) { + // TODO: report error to CameraDevice + Log.e(TAG, "Interrupted while waiting for requests to complete."); + } mDeviceState.setIdle(); stopPreview(); break; @@ -603,39 +603,41 @@ public class RequestThreadManager { if (!mParams.same(legacyRequest.parameters)) { mParams = legacyRequest.parameters; mCamera.setParameters(mParams); + paramsChanged = true; } } - mDeviceState.setCaptureStart(holder); - long timestamp = 0; try { + boolean success = mCaptureCollector.queueRequest(holder, + mLastRequest, JPEG_FRAME_TIMEOUT, TimeUnit.MILLISECONDS); + + if (!success) { + Log.e(TAG, "Timed out while queueing capture request."); + } if (holder.hasPreviewTargets()) { - mReceivedPreview.close(); doPreviewCapture(holder); - if (!mReceivedPreview.block(PREVIEW_FRAME_TIMEOUT)) { - // TODO: report error to CameraDevice - Log.e(TAG, "Hit timeout for preview callback!"); - } - timestamp = mLastPreviewTimestamp; } if (holder.hasJpegTargets()) { + success = mCaptureCollector. + waitForPreviewsEmpty(PREVIEW_FRAME_TIMEOUT * + MAX_IN_FLIGHT_REQUESTS, TimeUnit.MILLISECONDS); + if (!success) { + Log.e(TAG, "Timed out waiting for prior requests to complete."); + } mReceivedJpeg.close(); doJpegCapture(holder); if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) { // TODO: report error to CameraDevice Log.e(TAG, "Hit timeout for jpeg callback!"); } - mInFlightJpeg = null; - timestamp = mLastJpegTimestamp; } } catch (IOException e) { - // TODO: err handling + // TODO: report error to CameraDevice throw new IOError(e); - } - - if (timestamp == 0) { - timestamp = SystemClock.elapsedRealtimeNanos(); + } catch (InterruptedException e) { + // TODO: report error to CameraDevice + Log.e(TAG, "Interrupted during capture.", e); } if (paramsChanged) { @@ -647,11 +649,6 @@ public class RequestThreadManager { // Update parameters to the latest that we think the camera is using mLastRequest.setParameters(mParams); } - - - CameraMetadataNative result = mMapper.cachedConvertResultMetadata( - mLastRequest, timestamp); - mDeviceState.setCaptureResult(holder, result); } if (DEBUG) { long totalTime = SystemClock.elapsedRealtimeNanos() - startTime; @@ -661,6 +658,16 @@ public class RequestThreadManager { break; case MSG_CLEANUP: mCleanup = true; + try { + boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT, + TimeUnit.MILLISECONDS); + if (!success) { + Log.e(TAG, "Timed out while queueing cleanup request."); + } + } catch (InterruptedException e) { + // TODO: report error to CameraDevice + Log.e(TAG, "Interrupted while waiting for requests to complete."); + } if (mGLThreadManager != null) { mGLThreadManager.quit(); } @@ -693,6 +700,7 @@ public class RequestThreadManager { String name = String.format("RequestThread-%d", cameraId); TAG = name; mDeviceState = checkNotNull(deviceState, "deviceState must not be null"); + mCaptureCollector = new CaptureCollector(MAX_IN_FLIGHT_REQUESTS, mDeviceState); mRequestThread = new RequestHandlerThread(name, mRequestHandlerCb); } diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java index fdf9ba06d41d..068726417a0f 100644 --- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java +++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java @@ -28,6 +28,7 @@ import android.opengl.GLES20; import android.opengl.Matrix; import android.text.format.Time; import android.util.Log; +import android.util.Pair; import android.util.Size; import android.view.Surface; import android.os.SystemProperties; @@ -599,41 +600,63 @@ public class SurfaceTextureRenderer { /** * Draw the current buffer in the {@link SurfaceTexture} returned from - * {@link #getSurfaceTexture()} into the given set of target surfaces. + * {@link #getSurfaceTexture()} into the set of target {@link Surface}s + * in the next request from the given {@link CaptureCollector}, or drop + * the frame if none is available. * * <p> - * The given surfaces must be a subset of the surfaces set in the last - * {@link #configureSurfaces(java.util.Collection)} call. + * Any {@link Surface}s targeted must be a subset of the {@link Surface}s + * set in the last {@link #configureSurfaces(java.util.Collection)} call. * </p> * - * @param targetSurfaces the surfaces to draw to. + * @param targetCollector the surfaces to draw to. */ - public void drawIntoSurfaces(Collection<Surface> targetSurfaces) { + public void drawIntoSurfaces(CaptureCollector targetCollector) { if ((mSurfaces == null || mSurfaces.size() == 0) && (mConversionSurfaces == null || mConversionSurfaces.size() == 0)) { return; } + boolean doTiming = targetCollector.hasPendingPreviewCaptures(); checkGlError("before updateTexImage"); - if (targetSurfaces == null) { - mSurfaceTexture.updateTexImage(); - return; + if (doTiming) { + beginGlTiming(); } - beginGlTiming(); - mSurfaceTexture.updateTexImage(); long timestamp = mSurfaceTexture.getTimestamp(); - addGlTimestamp(timestamp); + + Pair<RequestHolder, Long> captureHolder = targetCollector.previewCaptured(timestamp); + + // No preview request queued, drop frame. + if (captureHolder == null) { + Log.w(TAG, "Dropping preview frame."); + if (doTiming) { + endGlTiming(); + } + return; + } + + RequestHolder request = captureHolder.first; + + Collection<Surface> targetSurfaces = request.getHolderTargets(); + if (doTiming) { + addGlTimestamp(timestamp); + } List<Long> targetSurfaceIds = LegacyCameraDevice.getSurfaceIds(targetSurfaces); for (EGLSurfaceHolder holder : mSurfaces) { if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) { makeCurrent(holder.eglSurface); - drawFrame(mSurfaceTexture, holder.width, holder.height); - swapBuffers(holder.eglSurface); + try { + LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second); + drawFrame(mSurfaceTexture, holder.width, holder.height); + swapBuffers(holder.eglSurface); + } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { + Log.w(TAG, "Surface abandoned, dropping frame. ", e); + } } } for (EGLSurfaceHolder holder : mConversionSurfaces) { @@ -647,6 +670,7 @@ public class SurfaceTextureRenderer { try { int format = LegacyCameraDevice.detectSurfaceType(holder.surface); + LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second); LegacyCameraDevice.produceFrame(holder.surface, mPBufferPixels.array(), holder.width, holder.height, format); swapBuffers(holder.eglSurface); @@ -655,8 +679,11 @@ public class SurfaceTextureRenderer { } } } + targetCollector.previewProduced(); - endGlTiming(); + if (doTiming) { + endGlTiming(); + } } /** diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java index 898c74612ca6..83ebadd42614 100644 --- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java +++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java @@ -28,7 +28,7 @@ import android.os.RemoteException; import java.lang.reflect.Method; /** - * Translate camera service status_t return values into exceptions. + * Translate camera device status_t return values into exceptions. * * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance * @hide @@ -57,7 +57,7 @@ public class CameraBinderDecorator { public static final int EUSERS = -87; - private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener { + static class CameraBinderDecoratorListener implements Decorator.DecoratorListener { @Override public void onBeforeInvocation(Method m, Object[] args) { @@ -76,10 +76,9 @@ public class CameraBinderDecorator { public boolean onCatchException(Method m, Object[] args, Throwable t) { if (t instanceof DeadObjectException) { - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DISCONNECTED, + throw new CameraRuntimeException(CAMERA_DISCONNECTED, "Process hosting the camera service has died unexpectedly", - t)); + t); } else if (t instanceof RemoteException) { throw new UnsupportedOperationException("An unknown RemoteException was thrown" + " which should never happen.", t); @@ -112,26 +111,20 @@ public class CameraBinderDecorator { case BAD_VALUE: throw new IllegalArgumentException("Bad argument passed to camera service"); case DEAD_OBJECT: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DISCONNECTED)); + throw new CameraRuntimeException(CAMERA_DISCONNECTED); case EACCES: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DISABLED)); + throw new CameraRuntimeException(CAMERA_DISABLED); case EBUSY: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_IN_USE)); + throw new CameraRuntimeException(CAMERA_IN_USE); case EUSERS: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - MAX_CAMERAS_IN_USE)); + throw new CameraRuntimeException(MAX_CAMERAS_IN_USE); case ENODEV: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DISCONNECTED)); + throw new CameraRuntimeException(CAMERA_DISCONNECTED); case EOPNOTSUPP: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DEPRECATED_HAL)); + throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL); case INVALID_OPERATION: - UncheckedThrow.throwAnyException(new IllegalStateException( - "Illegal state encountered in camera service.")); + throw new IllegalStateException( + "Illegal state encountered in camera service."); } /** diff --git a/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java new file mode 100644 index 000000000000..c1fb6b10eb8e --- /dev/null +++ b/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java @@ -0,0 +1,70 @@ +/* + * 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 android.hardware.camera2.utils; + +import android.os.DeadObjectException; +import android.os.RemoteException; +import android.util.Log; + +import java.lang.reflect.Method; + +/** + * Translate camera service status_t return values into exceptions. + * + * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance + * @hide + */ +public class CameraServiceBinderDecorator extends CameraBinderDecorator { + + private static final String TAG = "CameraServiceBinderDecorator"; + + static class CameraServiceBinderDecoratorListener + extends CameraBinderDecorator.CameraBinderDecoratorListener { + + // Pass through remote exceptions, unlike CameraBinderDecorator + @Override + public boolean onCatchException(Method m, Object[] args, Throwable t) { + + if (t instanceof DeadObjectException) { + // Can sometimes happen (camera service died) + // Pass on silently + } else if (t instanceof RemoteException) { + // Some other kind of remote exception - this is not normal, so let's at least + // note it before moving on + Log.e(TAG, "Unexpected RemoteException from camera service call.", t); + } + // All other exceptions also get sent onward + return false; + } + + } + + /** + * <p> + * Wraps the type T with a proxy that will check 'status_t' return codes + * from the native side of the camera service, and throw Java exceptions + * automatically based on the code. + * </p> + * + * @param obj object that will serve as the target for all method calls + * @param <T> the type of the element you want to wrap. This must be an interface. + * @return a proxy that will intercept all invocations to obj + */ + public static <T> T newInstance(T obj) { + return Decorator.<T> newInstance(obj, new CameraServiceBinderDecoratorListener()); + } +} diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index ce7a2a422176..5397d49e9db9 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -487,6 +487,8 @@ public final class DisplayManager { * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}, * or {@link #VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE}. * @param callbacks Callbacks to call when the state of the {@link VirtualDisplay} changes + * @param handler The handler on which the listener should be invoked, or null + * if the listener should be invoked on the calling thread's looper. * @return The newly created virtual display, or null if the application could * not create the virtual display. * diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java index acf92f1d1b3a..d663714b485f 100644 --- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java +++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java @@ -67,6 +67,7 @@ public final class HdmiCecDeviceInfo implements Parcelable { // are immutable value. private final int mLogicalAddress; private final int mPhysicalAddress; + private final int mPortId; private final int mDeviceType; private final int mVendorId; private final String mDisplayName; @@ -80,11 +81,12 @@ public final class HdmiCecDeviceInfo implements Parcelable { public HdmiCecDeviceInfo createFromParcel(Parcel source) { int logicalAddress = source.readInt(); int physicalAddress = source.readInt(); + int portId = source.readInt(); int deviceType = source.readInt(); int vendorId = source.readInt(); String displayName = source.readString(); - return new HdmiCecDeviceInfo(logicalAddress, physicalAddress, deviceType, - vendorId, displayName); + return new HdmiCecDeviceInfo(logicalAddress, physicalAddress, portId, + deviceType, vendorId, displayName); } @Override @@ -98,15 +100,17 @@ public final class HdmiCecDeviceInfo implements Parcelable { * * @param logicalAddress logical address of HDMI-CEC device * @param physicalAddress physical address of HDMI-CEC device + * @param portId HDMI port ID (1 for HDMI1) * @param deviceType type of device * @param vendorId vendor id of device. Used for vendor specific command. * @param displayName name of device * @hide */ - public HdmiCecDeviceInfo(int logicalAddress, int physicalAddress, int deviceType, + public HdmiCecDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType, int vendorId, String displayName) { mLogicalAddress = logicalAddress; mPhysicalAddress = physicalAddress; + mPortId = portId; mDeviceType = deviceType; mDisplayName = displayName; mVendorId = vendorId; @@ -127,6 +131,13 @@ public final class HdmiCecDeviceInfo implements Parcelable { } /** + * Return the port ID. + */ + public int getPortId() { + return mPortId; + } + + /** * Return type of the device. For more details, refer constants between * {@link DEVICE_TV} and {@link DEVICE_INACTIVE}. */ @@ -179,6 +190,7 @@ public final class HdmiCecDeviceInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mLogicalAddress); dest.writeInt(mPhysicalAddress); + dest.writeInt(mPortId); dest.writeInt(mDeviceType); dest.writeInt(mVendorId); dest.writeString(mDisplayName); @@ -189,6 +201,7 @@ public final class HdmiCecDeviceInfo implements Parcelable { StringBuffer s = new StringBuffer(); s.append("logical_address: ").append(mLogicalAddress).append(", "); s.append("physical_address: ").append(mPhysicalAddress).append(", "); + s.append("port_id: ").append(mPortId).append(", "); s.append("device_type: ").append(mDeviceType).append(", "); s.append("vendor_id: ").append(mVendorId).append(", "); s.append("display_name: ").append(mDisplayName); @@ -204,6 +217,7 @@ public final class HdmiCecDeviceInfo implements Parcelable { HdmiCecDeviceInfo other = (HdmiCecDeviceInfo) obj; return mLogicalAddress == other.mLogicalAddress && mPhysicalAddress == other.mPhysicalAddress + && mPortId == other.mPortId && mDeviceType == other.mDeviceType && mVendorId == other.mVendorId && mDisplayName.equals(other.mDisplayName); diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index 521a439c2c57..55db1df5438d 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -69,69 +69,71 @@ public final class HdmiControlManager { public static final int RESULT_INCORRECT_MODE = 6; public static final int RESULT_COMMUNICATION_FAILED = 7; - // -- Message ids for display osd. - - /** Place holder for recording status message. Indicates the status of a recording. */ - public static final int MESSAGE_RECORDING_STATUS_MESSAGE_START = 0x100; + // --- One Touch Recording success result /** Recording currently selected source. Indicates the status of a recording. */ - public static final int MESSAGE_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x101; + public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x01; /** Recording Digital Service. Indicates the status of a recording. */ - public static final int MESSAGE_RECORDING_DIGITAL_SERVICE = 0x102; + public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 0x02; /** Recording Analogue Service. Indicates the status of a recording. */ - public static final int MESSAGE_RECORDING_ANALOGUE_SERVICE = 0x103; + public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 0x03; /** Recording External input. Indicates the status of a recording. */ - public static final int MESSAGE_RECORDING_EXTERNAL_INPUT = 0x104; + public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 0x04; + + // --- One Touch Record failure result /** No recording – unable to record Digital Service. No suitable tuner. */ - public static final int MESSAGE_NO_RECORDNIG_UNABLE_DIGITAL_SERVICE = 0x105; + public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 0x05; /** No recording – unable to record Analogue Service. No suitable tuner. */ - public static final int MESSAGE_NO_RECORDNIG_UNABLE_ANALOGUE_SERVICE = 0x106; + public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 0x06; /** * No recording – unable to select required service. as suitable tuner, but the requested * parameters are invalid or out of range for that tuner. */ - public static final int MESSAGE_NO_RECORDNIG_UNABLE_SELECTED_SERVICE = 0x107; + public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 0x07; /** No recording – invalid External plug number */ - public static final int MESSAGE_NO_RECORDNIG_INVALID_EXTERNAL_PLUG_NUMBER = 0x109; + public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 0x09; /** No recording – invalid External Physical Address */ - public static final int MESSAGE_NO_RECORDNIG_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x10A; + public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x0A; /** No recording – CA system not supported */ - public static final int MESSAGE_NO_RECORDNIG_UNSUPPORTED_CA = 0x10B; + public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 0x0B; /** No Recording – No or Insufficient CA Entitlements” */ - public static final int MESSAGE_NO_RECORDNIG_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x10C; + public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x0C; /** No recording – Not allowed to copy source. Source is “copy never”. */ - public static final int MESSAGE_NO_RECORDNIG_DISALLOW_TO_COPY = 0x10D; + public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 0x0D; /** No recording – No further copies allowed */ - public static final int MESSAGE_NO_RECORDNIG_DISALLOW_TO_FUTHER_COPIES = 0x10E; + public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 0x0E; /** No recording – No media */ - public static final int MESSAGE_NO_RECORDNIG_NO_MEDIA = 0x110; + public static final int ONE_TOUCH_RECORD_NO_MEDIA = 0x10; /** No recording – playing */ - public static final int MESSAGE_NO_RECORDNIG_PLAYING = 0x111; + public static final int ONE_TOUCH_RECORD_PLAYING = 0x11; /** No recording – already recording */ - public static final int MESSAGE_NO_RECORDNIG_ALREADY_RECORDING = 0x112; + public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 0x12; /** No recording – media protected */ - public static final int MESSAGE_NO_RECORDNIG_MEDIA_PROTECTED = 0x113; + public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 0x13; /** No recording – no source signal */ - public static final int MESSAGE_NO_RECORDNIG_NO_SOURCE_SIGNAL = 0x114; + public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 0x14; /** No recording – media problem */ - public static final int MESSAGE_NO_RECORDNIG_MEDIA_PROBLEM = 0x115; + public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 0x15; /** No recording – not enough space available */ - public static final int MESSAGE_NO_RECORDNIG_NOT_ENOUGH_SPACE = 0x116; + public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 0x16; /** No recording – Parental Lock On */ - public static final int MESSAGE_NO_RECORDNIG_PARENT_LOCK_ON = 0x117; + public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 0x17; /** Recording terminated normally */ - public static final int MESSAGE_RECORDING_TERMINATED_NORMALLY = 0x11A; + public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 0x1A; /** Recording has already terminated */ - public static final int MESSAGE_RECORDING_ALREADY_TERMINATED = 0x11B; + public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 0x1B; /** No recording – other reason */ - public static final int MESSAGE_NO_RECORDNIG_OTHER_REASON = 0x11F; + public static final int ONE_TOUCH_RECORD_OTHER_REASON = 0x1F; // From here extra message for recording that is not mentioned in CEC spec /** No recording. Previous recording request in progress. */ - public static final int MESSAGE_NO_RECORDING_PREVIOUS_RECORDING_IN_PROGRESS = 0x130; + public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 0x30; /** No recording. Please check recorder and connection. */ - public static final int MESSAGE_NO_RECORDING_CHECK_RECORDER_CONNECTION = 0x131; + public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 0x31; /** Cannot record currently displayed source. */ - public static final int MESSAGE_NO_RECORDING_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x132; + public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x32; + /** CEC is disabled. */ + public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 0x33; + // --- Types for timer recording /** Timer recording type for digital service source. */ public static final int TIMER_RECORDING_TYPE_DIGITAL = 1; /** Timer recording type for analogue service source. */ @@ -139,6 +141,14 @@ public final class HdmiControlManager { /** Timer recording type for external source. */ public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3; + // --- Extra result value for timer recording. + /** No timer recording - check recorder and connection. */ + public static final int TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 0x01; + /** No timer recording - cannot record selected source. */ + public static final int TIME_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 0x02; + /** CEC is disabled. */ + public static final int TIME_RECORDING_RESULT_EXTRA_CEC_DISABLED = 0x33; + // True if we have a logical device of type playback hosted in the system. private final boolean mHasPlaybackDevice; // True if we have a logical device of type TV hosted in the system. diff --git a/core/java/android/hardware/hdmi/HdmiRecordListener.java b/core/java/android/hardware/hdmi/HdmiRecordListener.java new file mode 100644 index 000000000000..0b1166b7c0d7 --- /dev/null +++ b/core/java/android/hardware/hdmi/HdmiRecordListener.java @@ -0,0 +1,67 @@ +/* + * 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 android.hardware.hdmi; + +import android.annotation.SystemApi; +import android.hardware.hdmi.HdmiRecordSources.RecordSource; + +/** + * Listener for hdmi record feature including one touch record and timer recording. + * @hide + */ +@SystemApi +public abstract class HdmiRecordListener { + protected HdmiRecordListener() {} + + /** + * Called when TV received one touch record request from record device. The client of this + * should use {@link HdmiRecordSources} to return it. + * + * @param recorderAddress + * @return record source to be used for recording. Null if no device is available. + */ + public abstract RecordSource getOneTouchRecordSource(int recorderAddress); + + /** + * Called when one touch record is started or failed during initialization. + * + * @param result result code. For more details, please look at all constants starting with + * "ONE_TOUCH_RECORD_". Only + * {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE}, + * {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE}, + * {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE}, and + * {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT} mean normal + * start of recording; otherwise, describes failure. + */ + public void onOneTouchRecordResult(int result) { + } + + /** + * Called when timer recording is started or failed during initialization. + * + * @param result The most significant three bytes may contain result of <Timer Status> + * while the least significant byte may have error message like + * {@link HdmiControlManager#TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION} + * or + * {@link HdmiControlManager #TIME_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE} + * . If the least significant byte has non zero value the most significant three bytes + * may have 0 value. + */ + // TODO: implement result parser. + public void onTimerRecordingResult(int result) { + } +} diff --git a/core/java/android/hardware/hdmi/HdmiRecordSources.java b/core/java/android/hardware/hdmi/HdmiRecordSources.java index 296cae6253d9..917d1d9dd08f 100644 --- a/core/java/android/hardware/hdmi/HdmiRecordSources.java +++ b/core/java/android/hardware/hdmi/HdmiRecordSources.java @@ -492,7 +492,7 @@ public final class HdmiRecordSources { /** Indicates that a service is identified by a logical or virtual channel number. */ private static final int DIGITAL_SERVICE_IDENTIFIED_BY_CHANNEL = 1; - private static final int EXTRA_DATA_SIZE = 7; + static final int EXTRA_DATA_SIZE = 7; /** * Type of identification. It should be one of DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID and @@ -609,7 +609,7 @@ public final class HdmiRecordSources { */ @SystemApi public static final class AnalogueServiceSource extends RecordSource { - private static final int EXTRA_DATA_SIZE = 4; + static final int EXTRA_DATA_SIZE = 4; /** Indicates the Analogue broadcast type. */ private final int mBroadcastType; @@ -668,7 +668,7 @@ public final class HdmiRecordSources { */ @SystemApi public static final class ExternalPlugData extends RecordSource { - private static final int EXTRA_DATA_SIZE = 1; + static final int EXTRA_DATA_SIZE = 1; /** External Plug number on the Recording Device. */ private final int mPlugNumber; @@ -713,7 +713,7 @@ public final class HdmiRecordSources { */ @SystemApi public static final class ExternalPhysicalAddress extends RecordSource { - private static final int EXTRA_DATA_SIZE = 2; + static final int EXTRA_DATA_SIZE = 2; private final int mPhysicalAddress; @@ -751,6 +751,7 @@ public final class HdmiRecordSources { * Check the byte array of record source. * @hide */ + @SystemApi public static boolean checkRecordSource(byte[] recordSource) { int recordSourceType = recordSource[0]; int extraDataSize = recordSource.length - 1; diff --git a/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java b/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java index 3e5e49bbd97f..01b4dd3b269e 100644 --- a/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java +++ b/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java @@ -16,6 +16,10 @@ package android.hardware.hdmi; +import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE; +import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL; +import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL; + import android.annotation.SystemApi; import android.hardware.hdmi.HdmiRecordSources.AnalogueServiceSource; import android.hardware.hdmi.HdmiRecordSources.DigitalServiceSource; @@ -420,4 +424,35 @@ public class HdmiTimerRecordSources { return getDataSize(false); } } + + /** + * Check the byte array of timer record source. + * @param sourcetype + * @param recordSource + * @hide + */ + @SystemApi + public static boolean checkTimerRecordSource(int sourcetype, byte[] recordSource) { + int recordSourceSize = recordSource.length - TimerInfo.BASIC_INFO_SIZE; + switch (sourcetype) { + case TIMER_RECORDING_TYPE_DIGITAL: + return DigitalServiceSource.EXTRA_DATA_SIZE == recordSourceSize; + case TIMER_RECORDING_TYPE_ANALOGUE: + return AnalogueServiceSource.EXTRA_DATA_SIZE == recordSourceSize; + case TIMER_RECORDING_TYPE_EXTERNAL: + int specifier = recordSource[TimerInfo.BASIC_INFO_SIZE]; + if (specifier == EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG) { + // One byte for specifier. + return ExternalPlugData.EXTRA_DATA_SIZE + 1 == recordSourceSize; + } else if (specifier == EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS) { + // One byte for specifier. + return ExternalPhysicalAddress.EXTRA_DATA_SIZE + 1 == recordSourceSize; + } else { + // Invalid specifier. + return false; + } + default: + return false; + } + } } diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java index 6080914e5936..34362871e230 100644 --- a/core/java/android/hardware/hdmi/HdmiTvClient.java +++ b/core/java/android/hardware/hdmi/HdmiTvClient.java @@ -15,10 +15,9 @@ */ package android.hardware.hdmi; -import static android.hardware.hdmi.HdmiRecordSources.RecordSource; -import static android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource; - import android.annotation.SystemApi; +import android.hardware.hdmi.HdmiRecordSources.RecordSource; +import android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource; import android.os.RemoteException; import android.util.Log; @@ -155,27 +154,15 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Callback interface to used to get notified when a record request from recorder device. - */ - public interface RecordRequestListener { - /** - * Called when tv receives request request from recorder device. When it's called, - * it should return record source in byte array so that hdmi control service - * can start recording with the given source info. - * - * @return {@link HdmiRecordSources} to be used to set recording info - */ - RecordSource onRecordRequestReceived(int recorderAddress); - } - - /** - * Set {@link RecordRequestListener} to hdmi control service. + * Set record listener + * + * @param listener */ - public void setOneTouchRecordRequestListener(RecordRequestListener listener) { + public void setRecordListener(HdmiRecordListener listener) { try { - mService.setOneTouchRecordRequestListener(getCallbackWrapper(listener)); + mService.setHdmiRecordListener(getListenerWrapper(listener)); } catch (RemoteException e) { - Log.e(TAG, "failed to set record request listener: ", e); + Log.e(TAG, "failed to set record listener.", e); } } @@ -282,13 +269,12 @@ public final class HdmiTvClient extends HdmiClient { }; } - private static IHdmiRecordRequestListener getCallbackWrapper( - final RecordRequestListener listener) { - return new IHdmiRecordRequestListener.Stub() { + private static IHdmiRecordListener getListenerWrapper(final HdmiRecordListener callback) { + return new IHdmiRecordListener.Stub() { @Override - public byte[] onRecordRequestReceived(int recorderAddress) throws RemoteException { + public byte[] getOneTouchRecordSource(int recorderAddress) { HdmiRecordSources.RecordSource source = - listener.onRecordRequestReceived(recorderAddress); + callback.getOneTouchRecordSource(recorderAddress); if (source == null) { return EmptyArray.BYTE; } @@ -296,6 +282,16 @@ public final class HdmiTvClient extends HdmiClient { source.toByteArray(true, data, 0); return data; } + + @Override + public void onOneTouchRecordResult(int result) { + callback.onOneTouchRecordResult(result); + } + + @Override + public void onTimerRecordingResult(int result) { + callback.onTimerRecordingResult(result); + } }; } } diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index 95e0ee0a1307..808e0c9d572e 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -22,7 +22,7 @@ import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.hdmi.IHdmiDeviceEventListener; import android.hardware.hdmi.IHdmiHotplugEventListener; import android.hardware.hdmi.IHdmiInputChangeListener; -import android.hardware.hdmi.IHdmiRecordRequestListener; +import android.hardware.hdmi.IHdmiRecordListener; import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; import android.hardware.hdmi.IHdmiVendorCommandListener; @@ -62,7 +62,7 @@ interface IHdmiControlService { void sendVendorCommand(int deviceType, int targetAddress, in byte[] params, boolean hasVendorId); void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType); - void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener); + void setHdmiRecordListener(IHdmiRecordListener callback); void startOneTouchRecord(int recorderAddress, in byte[] recordSource); void stopOneTouchRecord(int recorderAddress); void startTimerRecording(int recorderAddress, int sourceType, in byte[] recordSource); diff --git a/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl b/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl new file mode 100644 index 000000000000..fba4b054996d --- /dev/null +++ b/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl @@ -0,0 +1,42 @@ +/* + * 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 android.hardware.hdmi; + +/** + * @hide + */ + interface IHdmiRecordListener { + /** + * Called when TV received one touch record request from record device. + * + * @param recorderAddress + * @return record source in byte array. + */ + byte[] getOneTouchRecordSource(int recorderAddress); + + /** + * Called when one touch record is started or failed during initialization. + * + * @param result result code for one touch record + */ + void onOneTouchRecordResult(int result); + /** + * Called when timer recording is started or failed during initialization. + * @param result result code for timer recording + */ + void onTimerRecordingResult(int result); + }
\ No newline at end of file diff --git a/core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl b/core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl deleted file mode 100644 index f8f9e5f698a1..000000000000 --- a/core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 android.hardware.hdmi; - -/** - * Callback interface definition for HDMI client to fill record source info - * when it gets record start request. - * - * @hide - */ -interface IHdmiRecordRequestListener { - byte[] onRecordRequestReceived(int recorderAddress); -}
\ No newline at end of file diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl index 038d7ef36b71..0bf4f25314e1 100644 --- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl +++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl @@ -16,6 +16,8 @@ package android.hardware.soundtrigger; +import android.hardware.soundtrigger.SoundTrigger; + /** * @hide */ @@ -27,7 +29,7 @@ oneway interface IRecognitionStatusCallback { * TODO: See if the data being passed in works well, if not use shared memory. * This *MUST* not exceed 100K. */ - void onDetected(in byte[] data); + void onDetected(in SoundTrigger.RecognitionEvent recognitionEvent); /** * Called when the detection for the associated keyphrase stops. */ diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl index 837691a9c2c2..9adc6bc6e88b 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl @@ -21,4 +21,5 @@ parcelable SoundTrigger.Keyphrase; parcelable SoundTrigger.KeyphraseRecognitionExtra; parcelable SoundTrigger.KeyphraseSoundModel; parcelable SoundTrigger.ModuleProperties; -parcelable SoundTrigger.RecognitionConfig;
\ No newline at end of file +parcelable SoundTrigger.RecognitionConfig; +parcelable SoundTrigger.RecognitionEvent;
\ No newline at end of file diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index 9a5cd9b814c4..3e8436851638 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -347,12 +347,7 @@ public class SoundTrigger { private static KeyphraseSoundModel fromParcel(Parcel in) { UUID uuid = UUID.fromString(in.readString()); - byte[] data = null; - int dataLength = in.readInt(); - if (dataLength >= 0) { - data = new byte[dataLength]; - in.readByteArray(data); - } + byte[] data = in.readBlob(); Keyphrase[] keyphrases = in.createTypedArray(Keyphrase.CREATOR); return new KeyphraseSoundModel(uuid, data, keyphrases); } @@ -365,12 +360,7 @@ public class SoundTrigger { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(uuid.toString()); - if (data != null) { - dest.writeInt(data.length); - dest.writeByteArray(data); - } else { - dest.writeInt(-1); - } + dest.writeBlob(data); dest.writeTypedArray(keyphrases, 0); } @@ -406,7 +396,7 @@ public class SoundTrigger { * {@link StatusListener#onRecognition(RecognitionEvent)} * callback upon recognition success or failure. */ - public static class RecognitionEvent { + public static class RecognitionEvent implements Parcelable { /** Recognition status e.g {@link #RECOGNITION_STATUS_SUCCESS} */ public final int status; /** Sound Model corresponding to this event callback */ @@ -425,7 +415,7 @@ public class SoundTrigger { * typically during enrollment. */ public final byte[] data; - RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, + public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, byte[] data) { this.status = status; this.soundModelHandle = soundModelHandle; @@ -435,6 +425,85 @@ public class SoundTrigger { this.capturePreambleMs = capturePreambleMs; this.data = data; } + + public static final Parcelable.Creator<RecognitionEvent> CREATOR + = new Parcelable.Creator<RecognitionEvent>() { + public RecognitionEvent createFromParcel(Parcel in) { + return RecognitionEvent.fromParcel(in); + } + + public RecognitionEvent[] newArray(int size) { + return new RecognitionEvent[size]; + } + }; + + private static RecognitionEvent fromParcel(Parcel in) { + int status = in.readInt(); + int soundModelHandle = in.readInt(); + boolean captureAvailable = in.readByte() == 1; + int captureSession = in.readInt(); + int captureDelayMs = in.readInt(); + int capturePreambleMs = in.readInt(); + byte[] data = in.readBlob(); + return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession, + captureDelayMs, capturePreambleMs, data); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(status); + dest.writeInt(soundModelHandle); + dest.writeByte((byte) (captureAvailable ? 1 : 0)); + dest.writeInt(captureSession); + dest.writeInt(captureDelayMs); + dest.writeInt(capturePreambleMs); + dest.writeBlob(data); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (captureAvailable ? 1231 : 1237); + result = prime * result + captureDelayMs; + result = prime * result + capturePreambleMs; + result = prime * result + captureSession; + result = prime * result + Arrays.hashCode(data); + result = prime * result + soundModelHandle; + result = prime * result + status; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RecognitionEvent other = (RecognitionEvent) obj; + if (captureAvailable != other.captureAvailable) + return false; + if (captureDelayMs != other.captureDelayMs) + return false; + if (capturePreambleMs != other.capturePreambleMs) + return false; + if (captureSession != other.captureSession) + return false; + if (!Arrays.equals(data, other.data)) + return false; + if (soundModelHandle != other.soundModelHandle) + return false; + if (status != other.status) + return false; + return true; + } } /** @@ -475,12 +544,7 @@ public class SoundTrigger { boolean captureRequested = in.readByte() == 1; KeyphraseRecognitionExtra[] keyphrases = in.createTypedArray(KeyphraseRecognitionExtra.CREATOR); - byte[] data = null; - int dataLength = in.readInt(); - if (dataLength >= 0) { - data = new byte[dataLength]; - in.readByteArray(data); - } + byte[] data = in.readBlob(); return new RecognitionConfig(captureRequested, keyphrases, data); } @@ -488,12 +552,7 @@ public class SoundTrigger { public void writeToParcel(Parcel dest, int flags) { dest.writeByte((byte) (captureRequested ? 1 : 0)); dest.writeTypedArray(keyphrases, 0); - if (data != null) { - dest.writeInt(data.length); - dest.writeByteArray(data); - } else { - dest.writeInt(-1); - } + dest.writeBlob(data); } @Override diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index e31f012c3d6c..30be4da5191f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1196,7 +1196,7 @@ public class ConnectivityManager { }; } - private HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests = + private static HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests = new HashMap<NetworkCapabilities, LegacyRequest>(); private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) { @@ -2068,9 +2068,9 @@ public class ConnectivityManager { /** {@hide} */ public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, - NetworkCapabilities nc, int score) { + NetworkCapabilities nc, int score, NetworkMisc misc) { try { - mService.registerNetworkAgent(messenger, ni, lp, nc, score); + mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc); } catch (RemoteException e) { } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 8b12fb84273a..671df24b349d 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -22,6 +22,7 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.net.NetworkMisc; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkState; @@ -64,11 +65,6 @@ interface IConnectivityManager NetworkQuotaInfo getActiveNetworkQuotaInfo(); boolean isActiveNetworkMetered(); - int startUsingNetworkFeature(int networkType, in String feature, - in IBinder binder); - - int stopUsingNetworkFeature(int networkType, in String feature); - boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); /** Policy control over specific {@link NetworkStateTracker}. */ @@ -150,7 +146,7 @@ interface IConnectivityManager void unregisterNetworkFactory(in Messenger messenger); void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, - in NetworkCapabilities nc, int score); + in NetworkCapabilities nc, int score, in NetworkMisc misc); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, in Messenger messenger, int timeoutSec, in IBinder binder, int legacy); diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 9a22d78256c0..97238f19e1f6 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -23,11 +23,16 @@ import android.os.Parcel; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.MalformedURLException; import java.net.Socket; import java.net.SocketException; import java.net.UnknownHostException; +import java.net.URL; import javax.net.SocketFactory; +import com.android.okhttp.HostResolver; +import com.android.okhttp.OkHttpClient; + /** * Identifies a {@code Network}. This is supplied to applications via * {@link ConnectivityManager.NetworkCallback} in response to the active @@ -44,7 +49,11 @@ public class Network implements Parcelable { */ public final int netId; + // Objects used to perform per-network operations such as getSocketFactory + // and getBoundURL, and a lock to protect access to them. private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; + private OkHttpClient mOkHttpClient = null; + private Object mLock = new Object(); /** * @hide @@ -166,12 +175,38 @@ public class Network implements Parcelable { * {@code Network}. */ public SocketFactory getSocketFactory() { - if (mNetworkBoundSocketFactory == null) { - mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); + synchronized (mLock) { + if (mNetworkBoundSocketFactory == null) { + mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); + } } return mNetworkBoundSocketFactory; } + /** + * Returns a {@link URL} based on the given URL but bound to this {@code Network}. + * Note that if this {@code Network} ever disconnects, this factory and any URL object it + * produced in the past or future will cease to work. + * + * @return a {@link URL} bound to this {@code Network}. + */ + public URL getBoundURL(URL url) throws MalformedURLException { + synchronized (mLock) { + if (mOkHttpClient == null) { + HostResolver hostResolver = new HostResolver() { + @Override + public InetAddress[] getAllByName(String host) throws UnknownHostException { + return Network.this.getAllByName(host); + } + }; + mOkHttpClient = new OkHttpClient() + .setSocketFactory(getSocketFactory()) + .setHostResolver(hostResolver); + } + } + return new URL(url, "", mOkHttpClient.createURLStreamHandler(url.getProtocol())); + } + // implement the Parcelable interface public int describeContents() { return 0; diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 41eab021ee67..22da90e80ef1 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -106,8 +106,27 @@ public abstract class NetworkAgent extends Handler { */ public static final int EVENT_UID_RANGES_REMOVED = BASE + 6; + /** + * Sent by the NetworkAgent to ConnectivityService to block all routes for a certain address + * family (AF_INET or AF_INET6) on this Network. For VPNs only. + * obj = Integer representing the family (AF_INET or AF_INET6) + */ + public static final int EVENT_BLOCK_ADDRESS_FAMILY = BASE + 7; + + /** + * Sent by the NetworkAgent to ConnectivityService to unblock routes for a certain address + * family (AF_INET or AF_INET6) on this Network. For VPNs only. + * obj = Integer representing the family (AF_INET or AF_INET6) + */ + public static final int EVENT_UNBLOCK_ADDRESS_FAMILY = BASE + 8; + public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) { + this(looper, context, logTag, ni, nc, lp, score, null); + } + + public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, + NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { super(looper); LOG_TAG = logTag; mContext = context; @@ -119,7 +138,7 @@ public abstract class NetworkAgent extends Handler { ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), - new LinkProperties(lp), new NetworkCapabilities(nc), score); + new LinkProperties(lp), new NetworkCapabilities(nc), score, misc); } @Override @@ -224,6 +243,21 @@ public abstract class NetworkAgent extends Handler { } /** + * Called by the VPN code when it wants to block an address family from being routed, typically + * because the VPN network doesn't support that family. + */ + public void blockAddressFamily(int family) { + queueOrSendMessage(EVENT_BLOCK_ADDRESS_FAMILY, family); + } + + /** + * Called by the VPN code when it wants to unblock an address family from being routed. + */ + public void unblockAddressFamily(int family) { + queueOrSendMessage(EVENT_UNBLOCK_ADDRESS_FAMILY, family); + } + + /** * Called when ConnectivityService has indicated they no longer want this network. * The parent factory should (previously) have received indication of the change * as well, either canceling NetworkRequests or altering their score such that this diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/core/java/android/net/NetworkMisc.aidl index f5a657b098c4..c65583fb530a 100644 --- a/core/java/android/service/dreams/IDozeHardware.aidl +++ b/core/java/android/net/NetworkMisc.aidl @@ -14,11 +14,6 @@ * limitations under the License. */ -package android.service.dreams; +package android.net; -/** - * @hide - */ -interface IDozeHardware { - byte[] sendMessage(String msg, in byte[] arg); -} +parcelable NetworkMisc; diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java new file mode 100644 index 000000000000..34f6cf45638b --- /dev/null +++ b/core/java/android/net/NetworkMisc.java @@ -0,0 +1,57 @@ +/* + * 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 android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A grab-bag of information (metadata, policies, properties, etc) about a {@link Network}. + * + * @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. + */ + public boolean allowBypass; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(allowBypass ? 1 : 0); + } + + public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() { + @Override + public NetworkMisc createFromParcel(Parcel in) { + NetworkMisc networkMisc = new NetworkMisc(); + networkMisc.allowBypass = in.readInt() != 0; + return networkMisc; + } + + @Override + public NetworkMisc[] newArray(int size) { + return new NetworkMisc[size]; + } + }; +} diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index 3fd415fc9f6a..9b66997dae43 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -373,6 +373,7 @@ public class VpnService extends Service { throw new IllegalArgumentException("Bad address"); } mAddresses.add(new LinkAddress(address, prefixLength)); + mConfig.updateAllowedFamilies(address); return this; } @@ -413,6 +414,7 @@ public class VpnService extends Service { } } mRoutes.add(new RouteInfo(new LinkAddress(address, prefixLength), null)); + mConfig.updateAllowedFamilies(address); return this; } @@ -497,7 +499,14 @@ public class VpnService extends Service { * @return this {@link Builder} object to facilitate chaining of method calls. */ public Builder allowFamily(int family) { - // TODO + if (family == AF_INET) { + mConfig.allowIPv4 = true; + } else if (family == AF_INET6) { + mConfig.allowIPv6 = true; + } else { + throw new IllegalArgumentException(family + " is neither " + AF_INET + " nor " + + AF_INET6); + } return this; } @@ -563,7 +572,7 @@ public class VpnService extends Service { * @return this {@link Builder} object to facilitate chaining of method calls. */ public Builder allowBypass() { - // TODO + mConfig.allowBypass = true; return this; } diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index c1e6664f5487..d6ee8e0c9937 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -367,7 +367,7 @@ interface INetworkManagementService /** * Setup a new VPN. */ - void createVirtualNetwork(int netId, boolean hasDNS); + void createVirtualNetwork(int netId, boolean hasDNS, boolean secure); /** * Remove a network. @@ -404,4 +404,7 @@ interface INetworkManagementService void addInterfaceToLocalNetwork(String iface, in List<RouteInfo> routes); void removeInterfaceFromLocalNetwork(String iface); + + void blockAddressFamily(int family, int netId, String iface); + void unblockAddressFamily(int family, int netId, String iface); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 95cb9f3d7b08..a1c2aa1d3e60 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -246,6 +246,7 @@ public final class Parcel { private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue); private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len); + private static native void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len); private static native void nativeWriteInt(long nativePtr, int val); private static native void nativeWriteLong(long nativePtr, long val); private static native void nativeWriteFloat(long nativePtr, float val); @@ -255,6 +256,7 @@ public final class Parcel { private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val); private static native byte[] nativeCreateByteArray(long nativePtr); + private static native byte[] nativeReadBlob(long nativePtr); private static native int nativeReadInt(long nativePtr); private static native long nativeReadLong(long nativePtr); private static native float nativeReadFloat(long nativePtr); @@ -479,6 +481,17 @@ public final class Parcel { } /** + * Write a blob of data into the parcel at the current {@link #dataPosition}, + * growing {@link #dataCapacity} if needed. + * @param b Bytes to place into the parcel. + * {@hide} + * {@SystemApi} + */ + public final void writeBlob(byte[] b) { + nativeWriteBlob(mNativePtr, b, 0, (b != null) ? b.length : 0); + } + + /** * Write an integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ @@ -1700,6 +1713,15 @@ public final class Parcel { } /** + * Read a blob of data from the parcel and return it as a byte array. + * {@hide} + * {@SystemApi} + */ + public final byte[] readBlob() { + return nativeReadBlob(mNativePtr); + } + + /** * Read and return a String[] object from the parcel. * {@hide} */ diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 45edf28f3176..a506c42ccfe9 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -772,7 +772,7 @@ public class UserManager { * @return A label that combines the original label and a badge as * determined by the system. */ - public String getBadgedLabelForUser(String label, UserHandle user) { + public CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user) { UserInfo userInfo = getUserIfProfile(user.getIdentifier()); if (userInfo != null && userInfo.isManagedProfile()) { return Resources.getSystem().getString( @@ -782,6 +782,15 @@ public class UserManager { } /** + * Kept during L development to simplify updating unbundled apps. + * TODO: Remove after 2014-08-04 + * @hide + */ + public String getBadgedLabelForUser(String label, UserHandle user) { + return (String) getBadgedLabelForUser((CharSequence) label, user); + } + + /** * If the target user is a managed profile of the calling user or the caller * is itself a managed profile, then this returns a drawable to use as a small * icon to include in a view to distinguish it from the original icon. diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index d66fc0fc49c6..671f722fac10 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -113,7 +113,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_SET_STREAM_VOLUME: - mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0); + mAudioManager.setStreamVolume(mStreamType, mLastProgress, + AudioManager.FLAG_SHOW_UI_WARNINGS); break; case MSG_START_SAMPLE: onStartSample(); diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 1157704e01f5..47cfa7d44369 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -265,6 +265,12 @@ public class CallLog { public static final String VOICEMAIL_URI = "voicemail_uri"; /** + * Transcription of the call or voicemail entry. This will only be populated for call log + * entries of type {@link #VOICEMAIL_TYPE} that have valid transcriptions. + */ + public static final String TRANSCRIPTION = "transcription"; + + /** * Whether this item has been read or otherwise consumed by the user. * <p> * Unlike the {@link #NEW} field, which requires the user to have acknowledged the diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index d0dbd96b3d4d..03863ae7ff41 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -6802,6 +6802,21 @@ public final class ContactsContract { default: return com.android.internal.R.string.eventTypeCustom; } } + + /** + * Return a {@link CharSequence} that best describes the given type, + * possibly substituting the given {@link #LABEL} value + * for {@link #TYPE_CUSTOM}. + */ + public static final CharSequence getTypeLabel(Resources res, int type, + CharSequence label) { + if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) { + return label; + } else { + final int labelRes = getTypeResource(type); + return res.getText(labelRes); + } + } } /** @@ -8018,9 +8033,8 @@ public final class ContactsContract { * * <p> * By default, unpinned contacts will have a pinned position of - * {@link PinnedPositions#UNPINNED}, or {@link Integer#MAX_VALUE} (2^31 - 1). Client-provided - * pinned positions can be positive integers that range anywhere from 0 to - * {@link PinnedPositions#UNPINNED}. + * {@link PinnedPositions#UNPINNED}. Client-provided pinned positions can be positive + * integers that are greater than 1. * </p> */ public static final class PinnedPositions { @@ -8043,10 +8057,9 @@ public final class ContactsContract { public static final String UNDEMOTE_METHOD = "undemote"; /** - * Default value for the pinned position of an unpinned contact. Also equal to - * {@link Integer#MAX_VALUE}. + * Default value for the pinned position of an unpinned contact. Also equal to 0. */ - public static final int UNPINNED = 0x7FFFFFFF; + public static final int UNPINNED = 0; /** * Value of pinned position for a contact that a user has indicated should be considered diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 325917ea5372..d137f0c8e39e 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -256,6 +256,11 @@ public final class MediaStore { * object in the extra field. This is useful for applications that only need a small image. * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri * value of EXTRA_OUTPUT. + * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through + * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must + * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications. + * If you don't set a ClipData, it will be copied there for you when calling + * {@link Context#startActivity(Intent)}. * @see #EXTRA_OUTPUT */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @@ -276,6 +281,11 @@ public final class MediaStore { * object in the extra field. This is useful for applications that only need a small image. * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri * value of EXTRA_OUTPUT. + * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through + * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must + * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications. + * If you don't set a ClipData, it will be copied there for you when calling + * {@link Context#startActivity(Intent)}. * * @see #ACTION_IMAGE_CAPTURE * @see #EXTRA_OUTPUT @@ -294,6 +304,11 @@ public final class MediaStore { * where the video is written. If EXTRA_OUTPUT is not present the video will be * written to the standard location for videos, and the Uri of that location will be * returned in the data field of the Uri. + * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through + * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must + * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications. + * If you don't set a ClipData, it will be copied there for you when calling + * {@link Context#startActivity(Intent)}. * @see #EXTRA_OUTPUT * @see #EXTRA_VIDEO_QUALITY * @see #EXTRA_SIZE_LIMIT diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 34d7c802afa0..fe201cdec2ab 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -131,6 +131,31 @@ public final class Settings { "android.settings.AIRPLANE_MODE_SETTINGS"; /** + * Activity Action: Modify Airplane mode settings using the users voice. + * <p> + * In some cases, a matching Activity may not exist, so ensure you safeguard against this. + * <p> + * This intent MUST be started using + * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity + * startVoiceActivity}. + * <p> + * To tell which state airplane mode should be set to, add the + * {@link #EXTRA_AIRPLANE_MODE_ENABLED} extra to this Intent with the state specified. + * If there is no extra in this Intent, no changes will be made. + * <p> + * The activity should verify that + * {@link android.app.Activity#isVoiceInteraction isVoiceInteraction} returns true before + * modifying the setting. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_VOICE_CONTROL_AIRPLANE_MODE = + "android.settings.VOICE_CONTROL_AIRPLANE_MODE"; + + /** * Activity Action: Show settings for accessibility modules. * <p> * In some cases, a matching Activity may not exist, so ensure you @@ -207,7 +232,6 @@ public final class Settings { /** * Activity Action: Show settings to allow configuration of Wi-Fi. - * <p> * In some cases, a matching Activity may not exist, so ensure you * safeguard against this. @@ -780,6 +804,33 @@ public final class Settings { public static final String ACTION_ZEN_MODE_SETTINGS = "android.settings.ZEN_MODE_SETTINGS"; /** + * Activity Action: Modify zen mode settings. + * <p> + * In some cases, a matching Activity may not exist, so ensure you safeguard against this. + * <p> + * This intent MUST be started using + * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity + * startVoiceActivity}. + * <p> + * To tell which state zen mode should be set to, add the + * {@link #EXTRA_ZEN_MODE_INTERRUPTION_STATE} extra to this Intent with the state specified. + * If there is no extra in this Intent, no changes will be made. + * <p> + * The Activity should verify that + * {@link android.app.Activity#isVoiceInteraction isVoiceInteraction}. + * returns true before modifying the setting. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_VOICE_CONTROL_ZEN_MODE = + "android.settings.VOICE_CONTROL_ZEN_MODE"; + + /** * Activity Action: Show the regulatory information screen for the device. * <p> * In some cases, a matching Activity may not exist, so ensure you safeguard @@ -891,6 +942,27 @@ public final class Settings { public static final String EXTRA_INPUT_METHOD_ID = "input_method_id"; + /** + * Activity Extra: Enable or disable Airplane Mode. + * <p> + * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_AIRPLANE_MODE} + * intent as a boolean. + */ + public static final String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled"; + + /** + * Activity Extra: Modify the zen mode interruption state. + * <p> + * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_ZEN_MODE} + * intent as an integer. The value should be one of + * {@link android.provider.Settings.Global#ZEN_MODE_OFF}, + * {@link android.provider.Settings.Global#ZEN_MODE_IMPORTANT_INTERRUPTIONS}, + * {@link android.provider.Settings.Global#ZEN_MODE_NO_INTERRUPTIONS}. + * + * @hide + */ + public static final String EXTRA_ZEN_MODE_INTERRUPTION_STATE = "zen_mode_interruption_state"; + private static final String JID_RESOURCE_PREFIX = "android"; public static final String AUTHORITY = "settings"; @@ -4630,6 +4702,13 @@ public final class Settings { public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints"; /** + * Persisted playback time after a user confirmation of an unsafe volume level. + * + * @hide + */ + public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms"; + + /** * This are the settings to be backed up. * * NOTE: Settings are backed up and restored in the order they appear @@ -4839,6 +4918,14 @@ public final class Settings { public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/global"); /** + * Whether users are allowed to add more users or guest from lockscreen. + * <p> + * Type: int + * @hide + */ + public static final String ADD_USERS_WHEN_LOCKED = "add_users_when_locked"; + + /** * Setting whether the global gesture for enabling accessibility is enabled. * If this gesture is enabled the user will be able to perfrom it to enable * the accessibility state without visiting the settings app. diff --git a/core/java/android/service/dreams/DozeHardware.java b/core/java/android/service/dreams/DozeHardware.java deleted file mode 100644 index b5e7f436cd25..000000000000 --- a/core/java/android/service/dreams/DozeHardware.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * 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 android.service.dreams; - -import android.os.RemoteException; -import android.util.Log; - -/** - * Provides access to low-level hardware features that a dream may use to provide - * a richer user experience while dozing. - * <p> - * This class contains functions that should be called by the dream to configure - * hardware before starting to doze and allowing the application processor to suspend. - * For example, the dream may provide the hardware with enough information to render - * some content on its own without any further assistance from the application processor. - * </p><p> - * This object is obtained by calling {@link DreamService#getDozeHardware()}. - * </p> - * - * @hide experimental - */ -public final class DozeHardware { - private static final String TAG = "DozeHardware"; - - public static final String MSG_ENABLE_MCU = "enable_mcu"; - - public static final byte[] VALUE_ON = "on".getBytes(); - public static final byte[] VALUE_OFF = "off".getBytes(); - - private final IDozeHardware mHardware; - - DozeHardware(IDozeHardware hardware) { - mHardware = hardware; - } - - /** - * Sets whether to enable the microcontroller. - * - * @param enable If true, enables the MCU otherwise disables it. - */ - public void setEnableMcu(boolean enable) { - sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF); - } - - /** - * Sends a message to the doze hardware module. - * - * @param msg The name of the message to send. - * @param arg An optional argument data blob, may be null. - * @return A result data blob, may be null. - */ - public byte[] sendMessage(String msg, byte[] arg) { - if (msg == null) { - throw new IllegalArgumentException("msg must not be null"); - } - - try { - return mHardware.sendMessage(msg, arg); - } catch (RemoteException ex) { - Log.e(TAG, "Failed to send message to doze hardware module.", ex); - return null; - } - } -} diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 5cf8aa6a821d..7e04ae87bb4b 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -183,7 +183,6 @@ public class DreamService extends Service implements Window.Callback { private boolean mCanDoze; private boolean mDozing; private boolean mWindowless; - private DozeHardware mDozeHardware; private int mDozeScreenState = Display.STATE_UNKNOWN; private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; @@ -658,29 +657,6 @@ public class DreamService extends Service implements Window.Callback { } /** - * Gets an object that may be used to access low-level hardware features that a - * dream may use to provide a richer user experience while dozing. - * - * @return An instance of {@link DozeHardware} or null if this device does not offer - * hardware support for dozing. - * - * @hide For use by system UI components only. - */ - public DozeHardware getDozeHardware() { - if (mCanDoze && mDozeHardware == null && mWindowToken != null) { - try { - IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken); - if (hardware != null) { - mDozeHardware = new DozeHardware(hardware); - } - } catch (RemoteException ex) { - // system server died - } - } - return mDozeHardware; - } - - /** * Gets the screen state to use while dozing. * * @return The screen state to use while dozing, such as {@link Display#STATE_ON}, @@ -1084,7 +1060,6 @@ public class DreamService extends Service implements Window.Callback { else if (canDoze()) pw.print(" candoze"); pw.println(); if (canDoze()) { - pw.println(" doze hardware: " + mDozeHardware); pw.println(" doze screen state: " + Display.stateToString(mDozeScreenState)); pw.println(" doze screen brightness: " + mDozeScreenBrightness); } diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl index 648426cbce7d..be3f3b345824 100644 --- a/core/java/android/service/dreams/IDreamManager.aidl +++ b/core/java/android/service/dreams/IDreamManager.aidl @@ -20,7 +20,6 @@ import android.content.ComponentName; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.IBinder; -import android.service.dreams.IDozeHardware; /** @hide */ interface IDreamManager { @@ -34,5 +33,4 @@ interface IDreamManager { void finishSelf(in IBinder token, boolean immediate); void startDozing(in IBinder token, int screenState, int screenBrightness); void stopDozing(in IBinder token); - IDozeHardware getDozeHardware(in IBinder token); } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index d685cc5357ea..a8c08d55c003 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -27,6 +27,7 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra; import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; +import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; import android.os.AsyncTask; import android.os.Handler; import android.os.Message; @@ -133,10 +134,10 @@ public class AlwaysOnHotwordDetector { private final Handler mHandler; /** - * The sound model for the keyphrase, derived from the model management service - * (IVoiceInteractionManagerService). May be null if the keyphrase isn't enrolled yet. + * Indicates if there is a sound model enrolled for the keyphrase, + * derived from the model management service (IVoiceInteractionManagerService). */ - private KeyphraseSoundModel mEnrolledSoundModel; + private boolean mIsEnrolledForDetection; private int mAvailability = STATE_NOT_READY; /** @@ -257,7 +258,7 @@ public class AlwaysOnHotwordDetector { int code = STATUS_ERROR; try { code = mModelManagementService.startRecognition(mVoiceInteractionService, - mKeyphraseMetadata.id, mEnrolledSoundModel, mInternalCallback, + mKeyphraseMetadata.id, mInternalCallback, new RecognitionConfig( captureTriggerAudio, recognitionExtra, null /* additional data */)); } catch (RemoteException e) { @@ -380,10 +381,10 @@ public class AlwaysOnHotwordDetector { } @Override - public void onDetected(byte[] data) { + public void onDetected(RecognitionEvent recognitionEvent) { Slog.i(TAG, "onDetected"); Message message = Message.obtain(mHandler, MSG_HOTWORD_DETECTED); - message.obj = data; + message.obj = recognitionEvent.data; message.sendToTarget(); } @@ -417,14 +418,13 @@ public class AlwaysOnHotwordDetector { @Override public Void doInBackground(Void... params) { int availability = internalGetInitialAvailability(); - KeyphraseSoundModel soundModel = null; + boolean enrolled = false; // Fetch the sound model if the availability is one of the supported ones. if (availability == STATE_NOT_READY || availability == STATE_KEYPHRASE_UNENROLLED || availability == STATE_KEYPHRASE_ENROLLED) { - soundModel = - internalGetKeyphraseSoundModel(mKeyphraseMetadata.id); - if (soundModel == null) { + enrolled = internalGetIsEnrolled(mKeyphraseMetadata.id); + if (!enrolled) { availability = STATE_KEYPHRASE_UNENROLLED; } else { availability = STATE_KEYPHRASE_ENROLLED; @@ -436,8 +436,8 @@ public class AlwaysOnHotwordDetector { Slog.d(TAG, "Hotword availability changed from " + mAvailability + " -> " + availability); } + mIsEnrolledForDetection = enrolled; mAvailability = availability; - mEnrolledSoundModel = soundModel; notifyStateChangedLocked(); } return null; @@ -475,31 +475,14 @@ public class AlwaysOnHotwordDetector { /** * @return The corresponding {@link KeyphraseSoundModel} or null if none is found. */ - private KeyphraseSoundModel internalGetKeyphraseSoundModel(int keyphraseId) { - List<KeyphraseSoundModel> soundModels; + private boolean internalGetIsEnrolled(int keyphraseId) { try { - soundModels = mModelManagementService - .listRegisteredKeyphraseSoundModels(mVoiceInteractionService); - if (soundModels == null || soundModels.isEmpty()) { - Slog.i(TAG, "No available sound models for keyphrase ID: " + keyphraseId); - return null; - } - for (int i = 0; i < soundModels.size(); i++) { - KeyphraseSoundModel soundModel = soundModels.get(i); - if (soundModel.keyphrases == null || soundModel.keyphrases.length == 0) { - continue; - } - for (int j = 0; i < soundModel.keyphrases.length; j++) { - Keyphrase keyphrase = soundModel.keyphrases[j]; - if (keyphrase.id == keyphraseId) { - return soundModel; - } - } - } + return mModelManagementService.isEnrolledForKeyphrase( + mVoiceInteractionService, keyphraseId); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in listRegisteredKeyphraseSoundModels!"); } - return null; + return false; } } } diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 4bfcaff0826f..a36f06c79a58 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -926,7 +926,7 @@ public abstract class Layout { public float getLineMax(int line) { float margin = getParagraphLeadingMargin(line); float signedExtent = getLineExtent(line, false); - return margin + signedExtent >= 0 ? signedExtent : -signedExtent; + return margin + (signedExtent >= 0 ? signedExtent : -signedExtent); } /** @@ -936,7 +936,7 @@ public abstract class Layout { public float getLineWidth(int line) { float margin = getParagraphLeadingMargin(line); float signedExtent = getLineExtent(line, true); - return margin + signedExtent >= 0 ? signedExtent : -signedExtent; + return margin + (signedExtent >= 0 ? signedExtent : -signedExtent); } /** @@ -1571,6 +1571,16 @@ public abstract class Layout { int len = mt.mLen; boolean hasTabs = false; TabStops tabStops = null; + // leading margins should be taken into account when measuring a paragraph + int margin = 0; + if (text instanceof Spanned) { + Spanned spanned = (Spanned) text; + LeadingMarginSpan[] spans = getParagraphSpans(spanned, start, end, + LeadingMarginSpan.class); + for (LeadingMarginSpan lms : spans) { + margin += lms.getLeadingMargin(true); + } + } for (int i = 0; i < len; ++i) { if (chars[i] == '\t') { hasTabs = true; @@ -1588,7 +1598,7 @@ public abstract class Layout { } } tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops); - return tl.metrics(null); + return margin + tl.metrics(null); } finally { TextLine.recycle(tl); MeasuredText.recycle(mt); diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java index 1550297cedae..efcbdb31227c 100644 --- a/core/java/android/transition/ChangeBounds.java +++ b/core/java/android/transition/ChangeBounds.java @@ -170,7 +170,7 @@ public class ChangeBounds extends Transition { int endWidth = endRight - endLeft; int endHeight = endBottom - endTop; int numChanges = 0; - if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) { + if ((startWidth != 0 && startHeight != 0) || (endWidth != 0 && endHeight != 0)) { if (startLeft != endLeft || startTop != endTop) ++numChanges; if (startRight != endRight || startBottom != endBottom) ++numChanges; } diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 19672138b512..53220d0180b0 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -1623,12 +1623,14 @@ public abstract class Transition implements Cloneable { if (!mEnded) { ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators(); int numOldAnims = runningAnimators.size(); - WindowId windowId = sceneRoot.getWindowId(); - for (int i = numOldAnims - 1; i >= 0; i--) { - AnimationInfo info = runningAnimators.valueAt(i); - if (info.view != null && windowId.equals(info.windowId)) { - Animator anim = runningAnimators.keyAt(i); - anim.pause(); + if (sceneRoot != null) { + WindowId windowId = sceneRoot.getWindowId(); + for (int i = numOldAnims - 1; i >= 0; i--) { + AnimationInfo info = runningAnimators.valueAt(i); + if (info.view != null && windowId.equals(info.windowId)) { + Animator anim = runningAnimators.keyAt(i); + anim.pause(); + } } } if (mListeners != null && mListeners.size() > 0) { diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java index 363f97f34586..83c60af60880 100644 --- a/core/java/android/transition/TransitionSet.java +++ b/core/java/android/transition/TransitionSet.java @@ -371,6 +371,8 @@ public class TransitionSet extends Transition { private TransitionValuesMaps removeExcludes(TransitionValuesMaps values) { if (mTargetIds.isEmpty() && mTargetIdExcludes == null && mTargetTypeExcludes == null + && mTargetNames == null && mTargetTypes == null + && mTargetExcludes == null && mTargetNameExcludes == null && mTargets.isEmpty()) { return values; } diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java index c36421db9b06..6820f7785ec2 100644 --- a/core/java/android/util/PathParser.java +++ b/core/java/android/util/PathParser.java @@ -74,6 +74,9 @@ public class PathParser { * @return a deep copy of the <code>source</code>. */ public static PathDataNode[] deepCopyNodes(PathDataNode[] source) { + if (source == null) { + return null; + } PathDataNode[] copy = new PathParser.PathDataNode[source.length]; for (int i = 0; i < source.length; i ++) { copy[i] = new PathDataNode(source[i]); diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java index b2961e52b617..5e49d8ebee99 100644 --- a/core/java/android/view/GLES20RecordingCanvas.java +++ b/core/java/android/view/GLES20RecordingCanvas.java @@ -17,6 +17,7 @@ package android.view; import android.annotation.NonNull; +import android.annotation.Nullable; import android.util.Pools.SynchronizedPool; /** @@ -41,7 +42,6 @@ class GLES20RecordingCanvas extends GLES20Canvas { static GLES20RecordingCanvas obtain(@NonNull RenderNode node) { if (node == null) throw new IllegalArgumentException("node cannot be null"); - GLES20RecordingCanvas canvas = sPool.acquire(); if (canvas == null) { canvas = new GLES20RecordingCanvas(); @@ -58,4 +58,9 @@ class GLES20RecordingCanvas extends GLES20Canvas { long finishRecording() { return nFinishRecording(mRenderer); } + + @Override + public boolean isRecordingFor(Object o) { + return o == mNode; + } } diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 73c732184972..2d54acb8e3b1 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -17,9 +17,11 @@ package android.view; import android.annotation.NonNull; +import android.annotation.Nullable; import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; +import android.graphics.Rect; /** * <p>A display list records a series of graphics related operations and can replay @@ -294,13 +296,6 @@ public class RenderNode { // RenderProperty Setters /////////////////////////////////////////////////////////////////////////// - /** - * Set the caching property on the display list, which indicates whether the display list - * holds a layer. Layer display lists should avoid creating an alpha layer, since alpha is - * handled in the drawLayer operation directly (and more efficiently). - * - * @param caching true if the display list represents a hardware layer, false otherwise. - */ public boolean setLayerType(int layerType) { return nSetLayerType(mNativeRenderNode, layerType); } @@ -309,6 +304,14 @@ public class RenderNode { return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0); } + public boolean setClipBounds(@Nullable Rect rect) { + if (rect == null) { + return nSetClipBoundsEmpty(mNativeRenderNode); + } else { + return nSetClipBounds(mNativeRenderNode, rect.left, rect.top, rect.right, rect.bottom); + } + } + /** * Set whether the Render node should clip itself to its bounds. This property is controlled by * the view's parent. @@ -594,6 +597,9 @@ public class RenderNode { * @see #getScaleX() */ public boolean setScaleX(float scaleX) { + if (scaleX > 1000000) { + throw new IllegalArgumentException("Invalid scale: " + scaleX); + } return nSetScaleX(mNativeRenderNode, scaleX); } @@ -615,6 +621,9 @@ public class RenderNode { * @see #getScaleY() */ public boolean setScaleY(float scaleY) { + if (scaleY > 1000000) { + throw new IllegalArgumentException("Invalid scale: " + scaleY); + } return nSetScaleY(mNativeRenderNode, scaleY); } @@ -702,85 +711,45 @@ public class RenderNode { * @param left The left position, in pixels, of the display list * * @see View#setLeft(int) - * @see #getLeft() */ public boolean setLeft(int left) { return nSetLeft(mNativeRenderNode, left); } /** - * Returns the left position for the display list in pixels. - * - * @see #setLeft(int) - */ - public float getLeft() { - return nGetLeft(mNativeRenderNode); - } - - /** * Sets the top position for the display list. * * @param top The top position, in pixels, of the display list * * @see View#setTop(int) - * @see #getTop() */ public boolean setTop(int top) { return nSetTop(mNativeRenderNode, top); } /** - * Returns the top position for the display list in pixels. - * - * @see #setTop(int) - */ - public float getTop() { - return nGetTop(mNativeRenderNode); - } - - /** * Sets the right position for the display list. * * @param right The right position, in pixels, of the display list * * @see View#setRight(int) - * @see #getRight() */ public boolean setRight(int right) { return nSetRight(mNativeRenderNode, right); } /** - * Returns the right position for the display list in pixels. - * - * @see #setRight(int) - */ - public float getRight() { - return nGetRight(mNativeRenderNode); - } - - /** * Sets the bottom position for the display list. * * @param bottom The bottom position, in pixels, of the display list * * @see View#setBottom(int) - * @see #getBottom() */ public boolean setBottom(int bottom) { return nSetBottom(mNativeRenderNode, bottom); } /** - * Returns the bottom position for the display list in pixels. - * - * @see #setBottom(int) - */ - public float getBottom() { - return nGetBottom(mNativeRenderNode); - } - - /** * Sets the left and top positions for the display list * * @param left The left position of the display list, in pixels @@ -805,7 +774,7 @@ public class RenderNode { * * @see View#offsetLeftAndRight(int) */ - public boolean offsetLeftAndRight(float offset) { + public boolean offsetLeftAndRight(int offset) { return nOffsetLeftAndRight(mNativeRenderNode, offset); } @@ -817,7 +786,7 @@ public class RenderNode { * * @see View#offsetTopAndBottom(int) */ - public boolean offsetTopAndBottom(float offset) { + public boolean offsetTopAndBottom(int offset) { return nOffsetTopAndBottom(mNativeRenderNode, offset); } @@ -860,8 +829,8 @@ public class RenderNode { // Properties - private static native boolean nOffsetTopAndBottom(long renderNode, float offset); - private static native boolean nOffsetLeftAndRight(long renderNode, float offset); + private static native boolean nOffsetTopAndBottom(long renderNode, int offset); + private static native boolean nOffsetLeftAndRight(long renderNode, int offset); private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top, int right, int bottom); private static native boolean nSetBottom(long renderNode, int bottom); @@ -874,6 +843,9 @@ public class RenderNode { private static native boolean nSetLayerType(long renderNode, int layerType); private static native boolean nSetLayerPaint(long renderNode, long paint); private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds); + private static native boolean nSetClipBounds(long renderNode, int left, int top, + int right, int bottom); + private static native boolean nSetClipBoundsEmpty(long renderNode); private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject); private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve); private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top, @@ -902,10 +874,6 @@ public class RenderNode { private static native boolean nHasOverlappingRendering(long renderNode); private static native boolean nGetClipToOutline(long renderNode); private static native float nGetAlpha(long renderNode); - private static native float nGetLeft(long renderNode); - private static native float nGetTop(long renderNode); - private static native float nGetRight(long renderNode); - private static native float nGetBottom(long renderNode); private static native float nGetCameraDistance(long renderNode); private static native float nGetScaleX(long renderNode); private static native float nGetScaleY(long renderNode); diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index b033780bcf5e..d14f22653dd8 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -88,8 +88,8 @@ public class ThreadedRenderer extends HardwareRenderer { private final float mLightY; private final float mLightZ; private final float mLightRadius; - private final float mAmbientShadowAlpha; - private final float mSpotShadowAlpha; + private final int mAmbientShadowAlpha; + private final int mSpotShadowAlpha; private long mNativeProxy; private boolean mInitialized = false; @@ -104,8 +104,10 @@ public class ThreadedRenderer extends HardwareRenderer { mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0); mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); - mAmbientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0); - mSpotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0); + mAmbientShadowAlpha = Math.round( + 255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0)); + mSpotShadowAlpha = Math.round( + 255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0)); a.recycle(); long rootNodePtr = nCreateRootRenderNode(); @@ -208,7 +210,9 @@ public class ThreadedRenderer extends HardwareRenderer { mSurfaceHeight = height; } mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight); - nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight, lightX, mLightY, mLightZ, mLightRadius); + nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight, + lightX, mLightY, mLightZ, mLightRadius, + mAmbientShadowAlpha, mSpotShadowAlpha); } @Override @@ -453,7 +457,8 @@ public class ThreadedRenderer extends HardwareRenderer { private static native void nUpdateSurface(long nativeProxy, Surface window); private static native void nPauseSurface(long nativeProxy, Surface window); private static native void nSetup(long nativeProxy, int width, int height, - float lightX, float lightY, float lightZ, float lightRadius); + float lightX, float lightY, float lightZ, float lightRadius, + int ambientShadowAlpha, int spotShadowAlpha); private static native void nSetOpaque(long nativeProxy, boolean opaque); private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos, long recordDuration, float density); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0079cc9a337b..4c1c2f9f564a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -724,11 +724,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static boolean sIgnoreMeasureCache = false; /** - * Ignore the clipBounds of this view for the children. - */ - static boolean sIgnoreClipBoundsForChildren = false; - - /** * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when * calling setFlags. */ @@ -3558,9 +3553,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // of whether a layout was requested on that View. sIgnoreMeasureCache = targetSdkVersion < KITKAT; - // Older apps may need this to ignore the clip bounds - sIgnoreClipBoundsForChildren = targetSdkVersion < L; - sCompatibilityDone = true; } } @@ -14309,6 +14301,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mClipBounds = null; } } + mRenderNode.setClipBounds(mClipBounds); } /** @@ -14430,7 +14423,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * to be called from anywhere else other than ViewGroup.drawChild(). */ boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { - boolean useDisplayListProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated; + boolean usingRenderNodeProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated; boolean more = false; final boolean childHasIdentityMatrix = hasIdentityMatrix(); final int flags = parent.mGroupFlags; @@ -14471,7 +14464,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mRenderNode.setAnimationMatrix(null); mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; } - if (!useDisplayListProperties && + if (!usingRenderNodeProperties && (flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { final Transformation t = parent.getChildTransformation(); final boolean hasTransform = parent.getChildStaticTransformation(this, t); @@ -14519,7 +14512,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { switch (layerType) { case LAYER_TYPE_SOFTWARE: - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { hasDisplayList = canHaveDisplayList(); } else { buildDrawingCache(true); @@ -14527,7 +14520,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } break; case LAYER_TYPE_HARDWARE: - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { hasDisplayList = canHaveDisplayList(); } break; @@ -14539,8 +14532,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } - useDisplayListProperties &= hasDisplayList; - if (useDisplayListProperties) { + usingRenderNodeProperties &= hasDisplayList; + if (usingRenderNodeProperties) { renderNode = getDisplayList(); if (!renderNode.isValid()) { // Uncommon, but possible. If a view is removed from the hierarchy during the call @@ -14548,7 +14541,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // try to use it again. renderNode = null; hasDisplayList = false; - useDisplayListProperties = false; + usingRenderNodeProperties = false; } } @@ -14565,17 +14558,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, layerType != LAYER_TYPE_HARDWARE; int restoreTo = -1; - if (!useDisplayListProperties || transformToApply != null) { + if (!usingRenderNodeProperties || transformToApply != null) { restoreTo = canvas.save(); } if (offsetForScroll) { canvas.translate(mLeft - sx, mTop - sy); } else { - if (!useDisplayListProperties) { + if (!usingRenderNodeProperties) { canvas.translate(mLeft, mTop); } if (scalingRequired) { - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { // TODO: Might not need this if we put everything inside the DL restoreTo = canvas.save(); } @@ -14585,7 +14578,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha()); + float alpha = usingRenderNodeProperties ? 1 : (getAlpha() * getTransitionAlpha()); if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) { if (transformToApply != null || !childHasIdentityMatrix) { @@ -14599,7 +14592,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (transformToApply != null) { if (concatMatrix) { - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { renderNode.setAnimationMatrix(transformToApply.getMatrix()); } else { // Undo the scroll translation, apply the transformation matrix, @@ -14618,7 +14611,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - if (!childHasIdentityMatrix && !useDisplayListProperties) { + if (!childHasIdentityMatrix && !usingRenderNodeProperties) { canvas.translate(-transX, -transY); canvas.concat(getMatrix()); canvas.translate(transX, transY); @@ -14642,7 +14635,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, layerType != LAYER_TYPE_NONE) { layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG; } - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); } else if (layerType == LAYER_TYPE_NONE) { final int scrollX = hasDisplayList ? 0 : sx; @@ -14662,7 +14655,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) == ViewGroup.FLAG_CLIP_CHILDREN && - !useDisplayListProperties && cache == null) { + !usingRenderNodeProperties && cache == null) { if (offsetForScroll) { canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop)); } else { @@ -14674,7 +14667,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - if (!useDisplayListProperties && hasDisplayList) { + if (!usingRenderNodeProperties && hasDisplayList) { renderNode = getDisplayList(); if (!renderNode.isValid()) { // Uncommon, but possible. If a view is removed from the hierarchy during the call @@ -14687,7 +14680,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (hasNoCache) { boolean layerRendered = false; - if (layerType == LAYER_TYPE_HARDWARE && !useDisplayListProperties) { + if (layerType == LAYER_TYPE_HARDWARE && !usingRenderNodeProperties) { final HardwareLayer layer = getHardwareLayer(); if (layer != null && layer.isValid()) { mLayerPaint.setAlpha((int) (alpha * 255)); @@ -14774,7 +14767,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param canvas The Canvas to which the View is rendered. */ public void draw(Canvas canvas) { - if (mClipBounds != null) { + boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode); + if (mClipBounds != null && !usingRenderNodeProperties) { canvas.clipRect(mClipBounds); } final int privateFlags = mPrivateFlags; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 1028a0c1e8e3..27f493a5fb55 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3015,6 +3015,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ @Override protected void dispatchDraw(Canvas canvas) { + boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode); final int childrenCount = mChildrenCount; final View[] children = mChildren; int flags = mGroupFlags; @@ -3059,7 +3060,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager int clipSaveCount = 0; final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK; - boolean hasClipBounds = mClipBounds != null && !sIgnoreClipBoundsForChildren; + boolean hasClipBounds = mClipBounds != null && !usingRenderNodeProperties; boolean clippingNeeded = clipToPadding || hasClipBounds; if (clippingNeeded) { @@ -3087,7 +3088,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Only use the preordered list if not HW accelerated, since the HW pipeline will do the // draw reordering internally - final ArrayList<View> preorderedList = canvas.isHardwareAccelerated() + final ArrayList<View> preorderedList = usingRenderNodeProperties ? null : buildOrderedChildList(); final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); @@ -3326,7 +3327,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager child.mRenderNode.setClipToBounds(clipChildren); } } - invalidate(); + invalidate(true); } } @@ -3341,7 +3342,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public void setClipToPadding(boolean clipToPadding) { if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) { setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding); - invalidate(); + invalidate(true); } } diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java index 77d48e2db378..4f342315504f 100644 --- a/core/java/android/view/accessibility/AccessibilityCache.java +++ b/core/java/android/view/accessibility/AccessibilityCache.java @@ -40,16 +40,14 @@ final class AccessibilityCache { private final Object mLock = new Object(); - private final LongArray mTempLongArray = new LongArray(); - private final SparseArray<AccessibilityWindowInfo> mWindowCache = - new SparseArray<AccessibilityWindowInfo>(); + new SparseArray<>(); private final SparseArray<LongSparseArray<AccessibilityNodeInfo>> mNodeCache = - new SparseArray<LongSparseArray<AccessibilityNodeInfo>>(); + new SparseArray<>(); private final SparseArray<AccessibilityWindowInfo> mTempWindowArray = - new SparseArray<AccessibilityWindowInfo>(); + new SparseArray<>(); public void addWindow(AccessibilityWindowInfo window) { synchronized (mLock) { @@ -60,20 +58,18 @@ final class AccessibilityCache { } } - public void removeWindows(int[] windowIds) { + public void clearWindows() { synchronized (mLock) { - final int windowCount = windowIds.length; - for (int i = 0; i < windowCount; i++) { - final int windowId = windowIds[i]; - AccessibilityWindowInfo window = mWindowCache.get(windowId); + final int windowCount = mWindowCache.size(); + for (int i = windowCount - 1; i >= 0; i--) { + AccessibilityWindowInfo window = mWindowCache.valueAt(i); if (window != null) { if (DEBUG) { - Log.i(LOG_TAG, "Removing window: " + windowId); + Log.i(LOG_TAG, "Removing window: " + window.getId()); } window.recycle(); - mWindowCache.remove(windowId); + mWindowCache.removeAt(i); } - clearNodesForWindowLocked(windowIds[i]); } } } @@ -113,6 +109,10 @@ final class AccessibilityCache { case AccessibilityEvent.TYPE_VIEW_SCROLLED: { clearSubTreeLocked(event.getWindowId(), event.getSourceNodeId()); } break; + + case AccessibilityEvent.TYPE_WINDOWS_CHANGED: { + clearWindows(); + } break; } } @@ -183,7 +183,7 @@ final class AccessibilityCache { sortedWindows.put(window.getLayer(), window); } - List<AccessibilityWindowInfo> windows = new ArrayList<AccessibilityWindowInfo>(); + List<AccessibilityWindowInfo> windows = new ArrayList<>(); for (int i = windowCount - 1; i >= 0; i--) { AccessibilityWindowInfo window = sortedWindows.valueAt(i); windows.add(AccessibilityWindowInfo.obtain(window)); @@ -221,7 +221,7 @@ final class AccessibilityCache { final int windowId = info.getWindowId(); LongSparseArray<AccessibilityNodeInfo> nodes = mNodeCache.get(windowId); if (nodes == null) { - nodes = new LongSparseArray<AccessibilityNodeInfo>(); + nodes = new LongSparseArray<>(); mNodeCache.put(windowId, nodes); } @@ -233,23 +233,14 @@ final class AccessibilityCache { // children have been removed to remove the descendants that // are no longer present. final LongArray newChildrenIds = info.getChildNodeIds(); - if (newChildrenIds != null) { - // Cache the new ids as we will do some lookups. - LongArray newChildNodeIds = mTempLongArray; - final int newChildCount = newChildNodeIds.size(); - for (int i = 0; i < newChildCount; i++) { - newChildNodeIds.add(newChildrenIds.get(i)); - } - final int oldChildCount = oldInfo.getChildCount(); - for (int i = 0; i < oldChildCount; i++) { - final long oldChildId = oldInfo.getChildId(i); - if (newChildNodeIds.indexOf(oldChildId) < 0) { - clearSubTreeLocked(windowId, oldChildId); - } + final int oldChildCount = oldInfo.getChildCount(); + for (int i = 0; i < oldChildCount; i++) { + final long oldChildId = oldInfo.getChildId(i); + // If the child is no longer present, remove the sub-tree. + if (newChildrenIds == null || newChildrenIds.indexOf(oldChildId) < 0) { + clearSubTreeLocked(windowId, oldChildId); } - - newChildNodeIds.clear(); } // Also be careful if the parent has changed since the new @@ -397,7 +388,7 @@ final class AccessibilityCache { continue; } - ArraySet<AccessibilityNodeInfo> seen = new ArraySet<AccessibilityNodeInfo>(); + ArraySet<AccessibilityNodeInfo> seen = new ArraySet<>(); final int windowId = mNodeCache.keyAt(i); final int nodeCount = nodes.size(); @@ -408,6 +399,8 @@ final class AccessibilityCache { if (!seen.add(node)) { Log.e(LOG_TAG, "Duplicate node: " + node + " in window:" + windowId); + // Stop now as we potentially found a loop. + continue; } // Check for one accessibility focus. diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 4748402f41ff..db78ec5776c2 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -84,7 +84,7 @@ public final class AccessibilityInteractionClient private static final Object sStaticLock = new Object(); private static final LongSparseArray<AccessibilityInteractionClient> sClients = - new LongSparseArray<AccessibilityInteractionClient>(); + new LongSparseArray<>(); private final AtomicInteger mInteractionIdCounter = new AtomicInteger(); @@ -101,7 +101,7 @@ public final class AccessibilityInteractionClient private Message mSameThreadMessage; private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = - new SparseArray<IAccessibilityServiceConnection>(); + new SparseArray<>(); private static final AccessibilityCache sAccessibilityCache = new AccessibilityCache(); @@ -163,19 +163,6 @@ public final class AccessibilityInteractionClient } /** - * Gets the root {@link AccessibilityNodeInfo} in a given window. - * - * @param connectionId The id of a connection for interacting with the system. - * @param windowId The window id. - * @return The root {@link AccessibilityNodeInfo} if found, null otherwise. - */ - public AccessibilityNodeInfo getRootInWindow(int connectionId, int windowId) { - return findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId, - AccessibilityNodeInfo.ROOT_NODE_ID, false, - AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS); - } - - /** * Gets the info for a window. * * @param connectionId The id of a connection for interacting with the system. @@ -225,11 +212,17 @@ public final class AccessibilityInteractionClient try { IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { - // The system is just sending data for windows that we introspected - // and changed but not ones that appeared, so we have to always call - // into the system process. This is less expensice as opposed to - // sending all windows on every window change. - List<AccessibilityWindowInfo> windows = connection.getWindows(); + List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows(); + if (windows != null) { + if (DEBUG) { + Log.i(LOG_TAG, "Windows cache hit"); + } + return windows; + } + if (DEBUG) { + Log.i(LOG_TAG, "Windows cache miss"); + } + windows = connection.getWindows(); if (windows != null) { final int windowCount = windows.size(); for (int i = 0; i < windowCount; i++) { @@ -534,10 +527,6 @@ public final class AccessibilityInteractionClient sAccessibilityCache.onAccessibilityEvent(event); } - public void removeWindows(int[] windowIds) { - sAccessibilityCache.removeWindows(windowIds); - } - /** * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}. * @@ -603,8 +592,7 @@ public final class AccessibilityInteractionClient // instantiate new result list to avoid passing internal instances to clients. final boolean isIpcCall = (Binder.getCallingPid() != Process.myPid()); if (!isIpcCall) { - mFindAccessibilityNodeInfosResult = - new ArrayList<AccessibilityNodeInfo>(infos); + mFindAccessibilityNodeInfosResult = new ArrayList<>(infos); } else { mFindAccessibilityNodeInfosResult = infos; } @@ -795,8 +783,8 @@ public final class AccessibilityInteractionClient Log.e(LOG_TAG, "No root."); } // Check for duplicates. - HashSet<AccessibilityNodeInfo> seen = new HashSet<AccessibilityNodeInfo>(); - Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>(); + HashSet<AccessibilityNodeInfo> seen = new HashSet<>(); + Queue<AccessibilityNodeInfo> fringe = new LinkedList<>(); fringe.add(root); while (!fringe.isEmpty()) { AccessibilityNodeInfo current = fringe.poll(); diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index e1a7ba24b510..7c30d2a0bfb2 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -50,6 +50,12 @@ public class CookieManager { /** * Sets whether the application's {@link WebView} instances should send and * accept cookies. + * By default this is set to true and the WebView accepts cookies. + * <p> + * When this is true + * {@link CookieManager#setAcceptThirdPartyCookies setAcceptThirdPartyCookies} and + * {@link CookieManager#setAcceptFileSchemeCookies setAcceptFileSchemeCookies} + * can be used to control the policy for those specific types of cookie. * * @param accept whether {@link WebView} instances should send and accept * cookies @@ -82,8 +88,7 @@ public class CookieManager { * @param accept whether the {@link WebView} instance should accept * third party cookies */ - public synchronized void setAcceptThirdPartyCookies(WebView webview, - boolean accept) { + public void setAcceptThirdPartyCookies(WebView webview, boolean accept) { throw new MustOverrideException(); } @@ -292,9 +297,10 @@ public class CookieManager { /** * Sets whether the application's {@link WebView} instances should send and * accept cookies for file scheme URLs. - * Use of cookies with file scheme URLs is potentially insecure. Do not use - * this feature unless you can be sure that no unintentional sharing of - * cookie data can take place. + * Use of cookies with file scheme URLs is potentially insecure and turned + * off by default. + * Do not use this feature unless you can be sure that no unintentional + * sharing of cookie data can take place. * <p> * Note that calls to this method will have no effect if made after a * {@link WebView} or CookieManager instance has been created. diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java index ebfa46b2b37b..1c364c09346d 100644 --- a/core/java/android/webkit/CookieSyncManager.java +++ b/core/java/android/webkit/CookieSyncManager.java @@ -24,7 +24,7 @@ import android.util.Log; * @deprecated The WebView now automatically syncs cookies as necessary. * You no longer need to create or use the CookieSyncManager. * To manually force a sync you can use the CookieManager - * method {@link CookieManager#flush} which is synchronous + * method {@link CookieManager#flush} which is a synchronous * replacement for {@link #sync}. * <p> * diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index 03cb95235e38..35c959801894 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -16,6 +16,7 @@ package android.webkit; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.net.Uri; @@ -409,55 +410,93 @@ public class WebChromeClient { * * @see FileChooserParams */ - public boolean showFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, + public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { return false; } /** - * Parameters used in the {@link #showFileChooser} method. - * This is intended to be used as a read-only data struct by the application. + * UploadHelper simplifies file upload operations by providing helper methods that + * would handle most common file picker/media capture requests. The application + * can use the helper to build an intent to start a file picker, and then parse + * the result returned by the activity. + * + * How to use: + * 1. Create a helper using {@link FileChooserParams#getUploadHelper} + * 2. Build an intent using {@link UploadHelper#buildIntent} + * 3. Fire the intent using {@link android.app.Activity#startActivityForResult}. + * 4. Check for ActivityNotFoundException and take a user friendly action if thrown. + * 5. Listen the result using {@link android.app.Activity#onActivityResult} + * 6. Parse the result using {@link UploadHelper#parseResult} + * 7. Send the result using filePathCallback of {@link WebChromeClient#onShowFileChooser} */ - public static class FileChooserParams { - // Flags for mode - /** Bitflag for <code>mode</code> indicating multiple files maybe selected */ - public static final int MODE_OPEN_MULTIPLE = 1 << 0; - /** Bitflag for <code>mode</code> indicating a folder maybe selected. - * The implementation should enumerate all files selected by this operation */ - public static final int MODE_OPEN_FOLDER = 1 << 1; - /** Bitflag for <code>mode</code> indicating a non-existant filename maybe returned */ - public static final int MODE_SAVE = 1 << 2; + public static abstract class UploadHelper { + /** + * Returns an intent that would start a file picker for file selection/media capture. + */ + public abstract Intent buildIntent(); /** - * Bit-field of the <code>MODE_</code> flags. + * Parses the result returned by the file picker activity. * - * 0 indicates plain single file open. + * @param resultCode the integer result code returned by the file picker activity. + * @param data the intent returned by the file picker activity. + * @return the Uris of selected file(s) or null if the resultCode indicates + * activity canceled or any other error. + */ + public abstract Uri[] parseResult(int resultCode, Intent data); + } + + /** + * Parameters used in the {@link #onShowFileChooser} method. + */ + public static abstract class FileChooserParams { + /** Open single file. Requires that the file exists before allowing the user to pick it. */ + public static final int OPEN = 0; + /** Like Open but allows multiple files to be selected. */ + public static final int OPEN_MULTIPLE = 1; + /** Like Open but allows a folder to be selected. The implementation should enumerate + all files selected by this operation. */ + public static final int OPEN_FOLDER = 2; + /** Allows picking a nonexistent file and saving it. */ + public static final int SAVE = 3; + + /** + * Returns a helper to simplify choosing and uploading files. The helper builds a default + * intent that the application can send using startActivityForResult and processes the + * results. */ - public int mode; + public abstract UploadHelper getUploadHelper(); /** - * Comma-seperated list of acceptable MIME types. + * Returns file chooser mode. */ - public String acceptTypes; + public abstract int getMode(); /** - * true indicates a preference for a live media captured value (e.g. Camera, Microphone). - * - * Use <code>acceptTypes</code> to determine suitable capture devices. + * Returns an array of acceptable MIME types. The array will be empty if no + * acceptable types are specified. */ - public boolean capture; + public abstract String[] getAcceptTypes(); /** - * The title to use for this file selector, or null. + * Returns preference for a live media captured value (e.g. Camera, Microphone). + * True indicates capture is enabled, false disabled. * - * Maybe null, in which case a default title should be used. + * Use <code>getAcceptTypes</code> to determine suitable capture devices. + */ + public abstract boolean isCaptureEnabled(); + + /** + * Returns the title to use for this file selector, or null. If null a default + * title should be used. */ - public String title; + public abstract CharSequence getTitle(); /** - * Name of a default selection if appropriate, or null. + * The file path of a default selection if specified, or null. */ - public String defaultFilename; + public abstract String getDefaultFilename(); }; /** diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index cc41669659c4..e07a6e3d9081 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -88,7 +88,7 @@ import java.util.Map; * </pre> * <p>See {@link android.content.Intent} for more information.</p> * - * <p>To provide a WebView in your own Activity, include a {@code <WebView>} in your layout, + * <p>To provide a WebView in your own Activity, include a {@code <WebView>} in your layout, * or set the entire Activity window as a WebView during {@link * android.app.Activity#onCreate(Bundle) onCreate()}:</p> * <pre class="prettyprint"> @@ -1624,6 +1624,16 @@ public class WebView extends AbsoluteLayout } /** + * Enable drawing the entire HTML document at a significant performance + * cost. Call this to enable drawing and capturing HTML content outside of + * the WebView's viewport. This should be called before any WebViews are + * created. + */ + public static void enableSlowWholeDocumentDraw() { + getFactory().getStatics().enableSlowWholeDocumentDraw(); + } + + /** * Clears the highlighting surrounding text matches created by * {@link #findAllAsync}. */ diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java index 5ff265568380..48f3ca370454 100644 --- a/core/java/android/webkit/WebViewFactoryProvider.java +++ b/core/java/android/webkit/WebViewFactoryProvider.java @@ -64,6 +64,12 @@ public interface WebViewFactoryProvider { * {@link android.webkit.WebView#optOutDataReductionProxy() } */ void optOutDataReductionProxy(); + + /** + * Implements the API method: + * {@link android.webkit.WebView#setSlowWholeDocumentDrawEnabled(boolean) } + */ + void enableSlowWholeDocumentDraw(); } Statics getStatics(); diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index be7e0bc42909..2708525683b0 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -16,6 +16,7 @@ package android.widget; +import android.animation.ObjectAnimator; import android.annotation.Nullable; import android.content.Context; import android.content.res.ColorStateList; @@ -63,6 +64,9 @@ public abstract class AbsSeekBar extends ProgressBar { * progress. */ private int mKeyProgressIncrement = 1; + private ObjectAnimator mPositionAnimator; + private static final int PROGRESS_ANIMATION_DURATION = 250; + private static final int NO_ALPHA = 0xFF; private float mDisabledAlpha; @@ -361,18 +365,17 @@ public abstract class AbsSeekBar extends ProgressBar { void onProgressRefresh(float scale, boolean fromUser) { super.onProgressRefresh(scale, fromUser); - final Drawable thumb = mThumb; - if (thumb != null) { - setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE); - - // Since we draw translated, the drawable's bounds that it signals - // for invalidation won't be the actual bounds we want invalidated, - // so just invalidate this whole view. - invalidate(); + if (!isAnimationRunning()) { + setThumbPos(scale); } } @Override + void onAnimatePosition(float scale, boolean fromUser) { + setThumbPos(scale); + } + + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); @@ -414,6 +417,18 @@ public abstract class AbsSeekBar extends ProgressBar { return max > 0 ? getProgress() / (float) max : 0; } + private void setThumbPos(float scale) { + final Drawable thumb = mThumb; + if (thumb != null) { + setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE); + // Since we draw translated, the drawable's bounds that it signals + // for invalidation won't be the actual bounds we want invalidated, + // so just invalidate this whole view. + invalidate(); + + } + } + /** * Updates the thumb drawable bounds. * @@ -676,13 +691,13 @@ public abstract class AbsSeekBar extends ProgressBar { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: if (progress <= 0) break; - setProgress(progress - mKeyProgressIncrement, true); + animateSetProgress(progress - mKeyProgressIncrement); onKeyChange(); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (progress >= getMax()) break; - setProgress(progress + mKeyProgressIncrement, true); + animateSetProgress(progress + mKeyProgressIncrement); onKeyChange(); return true; } @@ -691,6 +706,38 @@ public abstract class AbsSeekBar extends ProgressBar { return super.onKeyDown(keyCode, event); } + boolean isAnimationRunning() { + return mPositionAnimator != null && mPositionAnimator.isRunning(); + } + + /** + * @hide + */ + @Override + public void setProgress(int progress, boolean fromUser) { + if (isAnimationRunning()) { + mPositionAnimator.cancel(); + } + super.setProgress(progress, fromUser); + } + + void animateSetProgress(int progress) { + float curProgress = isAnimationRunning() ? getAnimationPosition() : getProgress(); + + if (progress < 0) { + progress = 0; + } else if (progress > getMax()) { + progress = getMax(); + } + setProgressValueOnly(progress); + + mPositionAnimator = ObjectAnimator.ofFloat(this, "animationPosition", curProgress, + progress); + mPositionAnimator.setDuration(PROGRESS_ANIMATION_DURATION); + mPositionAnimator.setAutoCancel(true); + mPositionAnimator.start(); + } + @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 20c1aa4f1481..4a308099d5a3 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -242,6 +242,8 @@ public class ProgressBar extends View { private long mUiThreadId; private boolean mShouldStartAnimationDrawable; + private float mAnimationPosition; + private boolean mInDrawing; private boolean mAttached; private boolean mRefreshIsPosted; @@ -259,7 +261,7 @@ public class ProgressBar extends View { public ProgressBar(Context context) { this(context, null); } - + public ProgressBar(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.progressBarStyle); } @@ -276,9 +278,9 @@ public class ProgressBar extends View { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes); - + mNoInvalidate = true; - + final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable); if (progressDrawable != null) { // Calling this method can set mMaxHeight, make sure the corresponding @@ -297,11 +299,11 @@ public class ProgressBar extends View { mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior); final int resID = a.getResourceId( - com.android.internal.R.styleable.ProgressBar_interpolator, + com.android.internal.R.styleable.ProgressBar_interpolator, android.R.anim.linear_interpolator); // default to linear interpolator if (resID > 0) { setInterpolator(context, resID); - } + } setMax(a.getInt(R.styleable.ProgressBar_max, mMax)); @@ -386,12 +388,12 @@ public class ProgressBar extends View { * traverse layer and state list drawables. */ private Drawable tileify(Drawable drawable, boolean clip) { - + if (drawable instanceof LayerDrawable) { LayerDrawable background = (LayerDrawable) drawable; final int N = background.getNumberOfLayers(); Drawable[] outDrawables = new Drawable[N]; - + for (int i = 0; i < N; i++) { int id = background.getId(i); outDrawables[i] = tileify(background.getDrawable(i), @@ -399,13 +401,13 @@ public class ProgressBar extends View { } LayerDrawable newBg = new LayerDrawable(outDrawables); - + for (int i = 0; i < N; i++) { newBg.setId(i, background.getId(i)); } - + return newBg; - + } else if (drawable instanceof StateListDrawable) { StateListDrawable in = (StateListDrawable) drawable; StateListDrawable out = new StateListDrawable(); @@ -414,7 +416,7 @@ public class ProgressBar extends View { out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip)); } return out; - + } else if (drawable instanceof BitmapDrawable) { final BitmapDrawable bitmap = (BitmapDrawable) drawable; final Bitmap tileBitmap = bitmap.getBitmap(); @@ -434,7 +436,7 @@ public class ProgressBar extends View { return clip ? new ClipDrawable( shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL) : shapeDrawable; } - + return drawable; } @@ -442,7 +444,7 @@ public class ProgressBar extends View { final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 }; return new RoundRectShape(roundedCorners, null, null); } - + /** * Convert a AnimationDrawable for use as a barberpole animation. * Each frame of the animation is wrapped in a ClipDrawable and @@ -454,7 +456,7 @@ public class ProgressBar extends View { final int N = background.getNumberOfFrames(); AnimationDrawable newBg = new AnimationDrawable(); newBg.setOneShot(background.isOneShot()); - + for (int i = 0; i < N; i++) { Drawable frame = tileify(background.getFrame(i), true); frame.setLevel(10000); @@ -465,7 +467,7 @@ public class ProgressBar extends View { } return drawable; } - + /** * <p> * Initialize the progress bar's default values: @@ -506,7 +508,7 @@ public class ProgressBar extends View { * <p>Change the indeterminate mode for this progress bar. In indeterminate * mode, the progress is ignored and the progress bar shows an infinite * animation instead.</p> - * + * * If this progress bar's style only supports indeterminate mode (such as the circular * progress bars), then this will be ignored. * @@ -657,7 +659,7 @@ public class ProgressBar extends View { setIndeterminateDrawable(d); } - + /** * <p>Get the drawable used to draw the progress bar in * progress mode.</p> @@ -963,7 +965,7 @@ public class ProgressBar extends View { setProgressDrawable(d); } - + /** * @return The drawable currently used to draw the progress bar */ @@ -1014,7 +1016,7 @@ public class ProgressBar extends View { final int count = mRefreshData.size(); for (int i = 0; i < count; i++) { final RefreshData rd = mRefreshData.get(i); - doRefreshProgress(rd.id, rd.progress, rd.fromUser, true); + doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate); rd.recycle(); } mRefreshData.clear(); @@ -1029,10 +1031,12 @@ public class ProgressBar extends View { new SynchronizedPool<RefreshData>(POOL_MAX); public int id; - public int progress; + public float progress; public boolean fromUser; + public boolean animate; - public static RefreshData obtain(int id, int progress, boolean fromUser) { + public static RefreshData obtain(int id, float progress, boolean fromUser, + boolean animate) { RefreshData rd = sPool.acquire(); if (rd == null) { rd = new RefreshData(); @@ -1040,9 +1044,10 @@ public class ProgressBar extends View { rd.id = id; rd.progress = progress; rd.fromUser = fromUser; + rd.animate = animate; return rd; } - + public void recycle() { sPool.release(this); } @@ -1064,9 +1069,19 @@ public class ProgressBar extends View { layer.mutate().setTint(tint, tintMode); } - private synchronized void doRefreshProgress(int id, int progress, boolean fromUser, + private float getScale(float progress) { + return mMax > 0 ? progress / (float) mMax : 0; + } + + private synchronized void doRefreshProgress(int id, float progress, boolean fromUser, boolean callBackToApp) { - float scale = mMax > 0 ? (float) progress / (float) mMax : 0; + doRefreshProgress(id, progress, fromUser, callBackToApp, false); + } + + private synchronized void doRefreshProgress(int id, float progress, boolean fromUser, + boolean callBackToApp, boolean animate) { + float scale = getScale(progress); + final Drawable d = mCurrentDrawable; if (d != null) { Drawable progressDrawable = null; @@ -1083,27 +1098,65 @@ public class ProgressBar extends View { } else { invalidate(); } - - if (callBackToApp && id == R.id.progress) { - onProgressRefresh(scale, fromUser); + + if (id == R.id.progress) { + if (animate) { + onAnimatePosition(scale, fromUser); + } else if (callBackToApp) { + onProgressRefresh(scale, fromUser); + } } } + /** + * Called when a ProgressBar is animating its position. + * + * @param scale Current position/progress between 0 and 1. + * @param fromUser True if the progress change was initiated by the user. + */ + void onAnimatePosition(float scale, boolean fromUser) { + } + + /** + * Sets the progress value without going through the entire refresh process. + * + * @see #setProgress(int, boolean) + * @param progress The new progress, between 0 and {@link #getMax()} + */ + void setProgressValueOnly(int progress) { + mProgress = progress; + onProgressRefresh(getScale(progress), true); + } + + void setAnimationPosition(float position) { + mAnimationPosition = position; + refreshProgress(R.id.progress, position, true, true); + } + + float getAnimationPosition() { + return mAnimationPosition; + } + void onProgressRefresh(float scale, boolean fromUser) { if (AccessibilityManager.getInstance(mContext).isEnabled()) { scheduleAccessibilityEventSender(); } } - private synchronized void refreshProgress(int id, int progress, boolean fromUser) { + private synchronized void refreshProgress(int id, float progress, boolean fromUser) { + refreshProgress(id, progress, fromUser, false); + } + + private synchronized void refreshProgress(int id, float progress, boolean fromUser, + boolean animate) { if (mUiThreadId == Thread.currentThread().getId()) { - doRefreshProgress(id, progress, fromUser, true); + doRefreshProgress(id, progress, fromUser, true, animate); } else { if (mRefreshProgressRunnable == null) { mRefreshProgressRunnable = new RefreshProgressRunnable(); } - final RefreshData rd = RefreshData.obtain(id, progress, fromUser); + final RefreshData rd = RefreshData.obtain(id, progress, fromUser, animate); mRefreshData.add(rd); if (mAttached && !mRefreshIsPosted) { post(mRefreshProgressRunnable); @@ -1111,7 +1164,7 @@ public class ProgressBar extends View { } } } - + /** * <p>Set the current progress to the specified value. Does not do anything * if the progress bar is in indeterminate mode.</p> @@ -1121,13 +1174,13 @@ public class ProgressBar extends View { * @see #setIndeterminate(boolean) * @see #isIndeterminate() * @see #getProgress() - * @see #incrementProgressBy(int) + * @see #incrementProgressBy(int) */ @android.view.RemotableViewMethod public synchronized void setProgress(int progress) { setProgress(progress, false); } - + @android.view.RemotableViewMethod synchronized void setProgress(int progress, boolean fromUser) { if (mIndeterminate) { @@ -1153,7 +1206,7 @@ public class ProgressBar extends View { * Set the current secondary progress to the specified value. Does not do * anything if the progress bar is in indeterminate mode. * </p> - * + * * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()} * @see #setIndeterminate(boolean) * @see #isIndeterminate() @@ -1234,8 +1287,8 @@ public class ProgressBar extends View { * @param max the upper range of this progress bar * * @see #getMax() - * @see #setProgress(int) - * @see #setSecondaryProgress(int) + * @see #setProgress(int) + * @see #setSecondaryProgress(int) */ @android.view.RemotableViewMethod public synchronized void setMax(int max) { @@ -1252,13 +1305,13 @@ public class ProgressBar extends View { refreshProgress(R.id.progress, mProgress, false); } } - + /** * <p>Increase the progress bar's progress by the specified amount.</p> * * @param diff the amount by which the progress must be increased * - * @see #setProgress(int) + * @see #setProgress(int) */ public synchronized final void incrementProgressBy(int diff) { setProgress(mProgress + diff); @@ -1269,7 +1322,7 @@ public class ProgressBar extends View { * * @param diff the amount by which the secondary progress must be increased * - * @see #setSecondaryProgress(int) + * @see #setSecondaryProgress(int) */ public synchronized final void incrementSecondaryProgressBy(int diff) { setSecondaryProgress(mSecondaryProgress + diff); @@ -1292,13 +1345,13 @@ public class ProgressBar extends View { if (mInterpolator == null) { mInterpolator = new LinearInterpolator(); } - + if (mTransformation == null) { mTransformation = new Transformation(); } else { mTransformation.clear(); } - + if (mAnimation == null) { mAnimation = new AlphaAnimation(0.0f, 1.0f); } else { @@ -1449,7 +1502,7 @@ public class ProgressBar extends View { } mIndeterminateDrawable.setBounds(left, top, right, bottom); } - + if (mProgressDrawable != null) { mProgressDrawable.setBounds(0, 0, right, bottom); } @@ -1519,20 +1572,20 @@ public class ProgressBar extends View { setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0), resolveSizeAndState(dh, heightMeasureSpec, 0)); } - + @Override protected void drawableStateChanged() { super.drawableStateChanged(); updateDrawableState(); } - + private void updateDrawableState() { int[] state = getDrawableState(); - + if (mProgressDrawable != null && mProgressDrawable.isStateful()) { mProgressDrawable.setState(state); } - + if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) { mIndeterminateDrawable.setState(state); } @@ -1554,14 +1607,14 @@ public class ProgressBar extends View { static class SavedState extends BaseSavedState { int progress; int secondaryProgress; - + /** * Constructor called from {@link ProgressBar#onSaveInstanceState()} */ SavedState(Parcelable superState) { super(superState); } - + /** * Constructor called from {@link #CREATOR} */ @@ -1595,10 +1648,10 @@ public class ProgressBar extends View { // Force our ancestor class to save its state Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); - + ss.progress = mProgress; ss.secondaryProgress = mSecondaryProgress; - + return ss; } @@ -1606,7 +1659,7 @@ public class ProgressBar extends View { public void onRestoreInstanceState(Parcelable state) { SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); - + setProgress(ss.progress); setSecondaryProgress(ss.secondaryProgress); } @@ -1622,7 +1675,7 @@ public class ProgressBar extends View { final int count = mRefreshData.size(); for (int i = 0; i < count; i++) { final RefreshData rd = mRefreshData.get(i); - doRefreshProgress(rd.id, rd.progress, rd.fromUser, true); + doRefreshProgress(rd.id, rd.progress, rd.fromUser, rd.animate); rd.recycle(); } mRefreshData.clear(); diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 9b763c18cac5..1e30bfa3dcec 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -518,6 +518,9 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { if (mIs24HourMode) { if (mIsOnInnerCircle) { hours = hours % 12; + if (hours == 0) { + hours = 12; + } } else { if (hours != 0) { hours += 12; diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java index 82b490ea26c2..c4a7c0aa4efd 100644 --- a/core/java/android/widget/RatingBar.java +++ b/core/java/android/widget/RatingBar.java @@ -314,6 +314,10 @@ public class RatingBar extends AbsSeekBar { dispatchRatingChange(true); } + @Override + void animateSetProgress(int progress) { + } + void dispatchRatingChange(boolean fromUser) { if (mOnRatingBarChangeListener != null) { mOnRatingBarChangeListener.onRatingChanged(this, getRating(), diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 90e80d3122b6..4dd7e0793b22 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -195,6 +195,11 @@ public class RelativeLayout extends ViewGroup { LEFT_OF, RIGHT_OF, ALIGN_LEFT, ALIGN_RIGHT, START_OF, END_OF, ALIGN_START, ALIGN_END }; + /** + * Used to indicate left/right/top/bottom should be inferred from constraints + */ + private static final int VALUE_NOT_SET = Integer.MIN_VALUE; + private View mBaselineView = null; private boolean mHasBaselineAlignedChild; @@ -670,8 +675,8 @@ public class RelativeLayout extends ViewGroup { /** * Measure a child. The child should have left, top, right and bottom information - * stored in its LayoutParams. If any of these values is -1 it means that the view - * can extend up to the corresponding edge. + * stored in its LayoutParams. If any of these values is VALUE_NOT_SET it means + * that the view can extend up to the corresponding edge. * * @param child Child to measure * @param params LayoutParams associated with child @@ -744,11 +749,11 @@ public class RelativeLayout extends ViewGroup { int childSpecMode = 0; int childSpecSize = 0; - // Negative values in a mySize/myWidth/myWidth value in RelativeLayout + // Negative values in a mySize value in RelativeLayout // measurement is code for, "we got an unspecified mode in the // RelativeLayout's measure spec." if (mySize < 0 && !mAllowBrokenMeasureSpecs) { - if (childStart >= 0 && childEnd >= 0) { + if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) { // Constraints fixed both edges, so child has an exact size. childSpecSize = Math.max(0, childEnd - childStart); childSpecMode = MeasureSpec.EXACTLY; @@ -771,17 +776,17 @@ public class RelativeLayout extends ViewGroup { // If the view did not express a layout constraint for an edge, use // view's margins and our padding - if (tempStart < 0) { + if (tempStart == VALUE_NOT_SET) { tempStart = startPadding + startMargin; } - if (tempEnd < 0) { + if (tempEnd == VALUE_NOT_SET) { tempEnd = mySize - endPadding - endMargin; } // Figure out maximum size available to this view int maxAvailable = tempEnd - tempStart; - if (childStart >= 0 && childEnd >= 0) { + if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) { // Constraints fixed both edges, so child must be an exact size childSpecMode = MeasureSpec.EXACTLY; childSpecSize = maxAvailable; @@ -828,13 +833,13 @@ public class RelativeLayout extends ViewGroup { final int layoutDirection = getLayoutDirection(); int[] rules = params.getRules(layoutDirection); - if (params.mLeft < 0 && params.mRight >= 0) { + if (params.mLeft == VALUE_NOT_SET && params.mRight != VALUE_NOT_SET) { // Right is fixed, but left varies params.mLeft = params.mRight - child.getMeasuredWidth(); - } else if (params.mLeft >= 0 && params.mRight < 0) { + } else if (params.mLeft != VALUE_NOT_SET && params.mRight == VALUE_NOT_SET) { // Left is fixed, but right varies params.mRight = params.mLeft + child.getMeasuredWidth(); - } else if (params.mLeft < 0 && params.mRight < 0) { + } else if (params.mLeft == VALUE_NOT_SET && params.mRight == VALUE_NOT_SET) { // Both left and right vary if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) { if (!wrapContent) { @@ -864,13 +869,13 @@ public class RelativeLayout extends ViewGroup { int[] rules = params.getRules(); - if (params.mTop < 0 && params.mBottom >= 0) { + if (params.mTop == VALUE_NOT_SET && params.mBottom != VALUE_NOT_SET) { // Bottom is fixed, but top varies params.mTop = params.mBottom - child.getMeasuredHeight(); - } else if (params.mTop >= 0 && params.mBottom < 0) { + } else if (params.mTop != VALUE_NOT_SET && params.mBottom == VALUE_NOT_SET) { // Top is fixed, but bottom varies params.mBottom = params.mTop + child.getMeasuredHeight(); - } else if (params.mTop < 0 && params.mBottom < 0) { + } else if (params.mTop == VALUE_NOT_SET && params.mBottom == VALUE_NOT_SET) { // Both top and bottom vary if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) { if (!wrapContent) { @@ -891,12 +896,14 @@ public class RelativeLayout extends ViewGroup { private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) { RelativeLayout.LayoutParams anchorParams; - // -1 indicated a "soft requirement" in that direction. For example: - // left=10, right=-1 means the view must start at 10, but can go as far as it wants to the right - // left =-1, right=10 means the view must end at 10, but can go as far as it wants to the left + // VALUE_NOT_SET indicates a "soft requirement" in that direction. For example: + // left=10, right=VALUE_NOT_SET means the view must start at 10, but can go as far as it + // wants to the right + // left=VALUE_NOT_SET, right=10 means the view must end at 10, but can go as far as it + // wants to the left // left=10, right=20 means the left and right ends are both fixed - childParams.mLeft = -1; - childParams.mRight = -1; + childParams.mLeft = VALUE_NOT_SET; + childParams.mRight = VALUE_NOT_SET; anchorParams = getRelatedViewParams(rules, LEFT_OF); if (anchorParams != null) { @@ -947,8 +954,8 @@ public class RelativeLayout extends ViewGroup { int[] rules = childParams.getRules(); RelativeLayout.LayoutParams anchorParams; - childParams.mTop = -1; - childParams.mBottom = -1; + childParams.mTop = VALUE_NOT_SET; + childParams.mBottom = VALUE_NOT_SET; anchorParams = getRelatedViewParams(rules, ABOVE); if (anchorParams != null) { @@ -1222,9 +1229,6 @@ public class RelativeLayout extends ViewGroup { private int mLeft, mTop, mRight, mBottom; - private int mStart = DEFAULT_MARGIN_RELATIVE; - private int mEnd = DEFAULT_MARGIN_RELATIVE; - private boolean mRulesChanged = false; private boolean mIsRtlCompatibilityMode = false; @@ -1601,14 +1605,6 @@ public class RelativeLayout extends ViewGroup { @Override public void resolveLayoutDirection(int layoutDirection) { final boolean isLayoutRtl = isLayoutRtl(); - if (isLayoutRtl) { - if (mStart != DEFAULT_MARGIN_RELATIVE) mRight = mStart; - if (mEnd != DEFAULT_MARGIN_RELATIVE) mLeft = mEnd; - } else { - if (mStart != DEFAULT_MARGIN_RELATIVE) mLeft = mStart; - if (mEnd != DEFAULT_MARGIN_RELATIVE) mRight = mEnd; - } - if (hasRelativeRules() && layoutDirection != getLayoutDirection()) { resolveRules(layoutDirection); } diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java index 53d0839eb5fa..3bad235ebff5 100644 --- a/core/java/android/widget/SimpleMonthAdapter.java +++ b/core/java/android/widget/SimpleMonthAdapter.java @@ -142,14 +142,10 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli enabledDayRangeEnd = 31; } - drawingParams.put(SimpleMonthView.VIEW_PARAMS_SELECTED_DAY, selectedDay); - drawingParams.put(SimpleMonthView.VIEW_PARAMS_YEAR, year); - drawingParams.put(SimpleMonthView.VIEW_PARAMS_MONTH, month); - drawingParams.put(SimpleMonthView.VIEW_PARAMS_WEEK_START, mController.getFirstDayOfWeek()); - drawingParams.put(SimpleMonthView.VIEW_PARAMS_ENABLEDDAYRANGE_START, enabledDayRangeStart); - drawingParams.put(SimpleMonthView.VIEW_PARAMS_ENABLEDDAYRANGE_END, enabledDayRangeEnd); - v.setMonthParams(drawingParams); + v.setMonthParams(selectedDay, month, year, mController.getFirstDayOfWeek(), + enabledDayRangeStart, enabledDayRangeEnd); v.invalidate(); + return v; } diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java index 7589711f815d..ab6da7c7c5ea 100644 --- a/core/java/android/widget/SimpleMonthView.java +++ b/core/java/android/widget/SimpleMonthView.java @@ -52,44 +52,6 @@ import java.util.Locale; class SimpleMonthView extends View { private static final String TAG = "SimpleMonthView"; - /** - * These params can be passed into the view to control how it appears. - * {@link #VIEW_PARAMS_WEEK} is the only required field, though the default - * values are unlikely to fit most layouts correctly. - */ - /** - * This sets the height of this week in pixels - */ - static final String VIEW_PARAMS_HEIGHT = "height"; - /** - * This specifies the position (or weeks since the epoch) of this week, - * calculated using - */ - static final String VIEW_PARAMS_MONTH = "month"; - /** - * This specifies the position (or weeks since the epoch) of this week, - * calculated using - */ - static final String VIEW_PARAMS_YEAR = "year"; - /** - * This sets one of the days in this view as selected {@link Time#SUNDAY} - * through {@link Time#SATURDAY}. - */ - static final String VIEW_PARAMS_SELECTED_DAY = "selected_day"; - /** - * Which day the week should start on. {@link Time#SUNDAY} through - * {@link Time#SATURDAY}. - */ - static final String VIEW_PARAMS_WEEK_START = "week_start"; - /** - * First enabled day. - */ - static final String VIEW_PARAMS_ENABLEDDAYRANGE_START = "enabled_day_range_start"; - /** - * Last enabled day. - */ - static final String VIEW_PARAMS_ENABLEDDAYRANGE_END = "enabled_day_range_end"; - private static int DEFAULT_HEIGHT = 32; private static int MIN_HEIGHT = 10; @@ -327,36 +289,38 @@ class SimpleMonthView extends View { drawDays(canvas); } + private static boolean isValidDay(int day) { + return (day >= Time.SUNDAY && day <= Time.SATURDAY); + } + /** - * Sets all the parameters for displaying this week. The only required - * parameter is the week number. Other parameters have a default value and - * will only update if a new value is included, except for focus month, - * which will always default to no focus month if no value is passed in. See - * {@link #VIEW_PARAMS_HEIGHT} for more info on parameters. + * Sets all the parameters for displaying this week. Parameters have a default value and + * will only update if a new value is included, except for focus month, which will always + * default to no focus month if no value is passed in. The only required parameter is the + * week start. * - * @param params A map of the new parameters, see - * {@link #VIEW_PARAMS_HEIGHT} + * @param selectedDay the selected day. + * @param month the month. + * @param year the year. + * @param weekStart which day the week should start on. {@link Time#SUNDAY} through + * {@link Time#SATURDAY}. + * @param enabledDayStart the first enabled day. + * @param enabledDayEnd the last enabled day. */ - void setMonthParams(HashMap<String, Integer> params) { - if (!params.containsKey(VIEW_PARAMS_MONTH) && !params.containsKey(VIEW_PARAMS_YEAR)) { - throw new InvalidParameterException( - "You must specify the month and year for this view"); - } - setTag(params); - // We keep the current value for any params not present - if (params.containsKey(VIEW_PARAMS_HEIGHT)) { - mRowHeight = params.get(VIEW_PARAMS_HEIGHT); - if (mRowHeight < MIN_HEIGHT) { - mRowHeight = MIN_HEIGHT; - } + void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart, + int enabledDayEnd) { + if (mRowHeight < MIN_HEIGHT) { + mRowHeight = MIN_HEIGHT; } - if (params.containsKey(VIEW_PARAMS_SELECTED_DAY)) { - mSelectedDay = params.get(VIEW_PARAMS_SELECTED_DAY); + + if (isValidDay(selectedDay)) { + mSelectedDay = selectedDay; } - // Allocate space for caching the day numbers and focus values - mMonth = params.get(VIEW_PARAMS_MONTH); - mYear = params.get(VIEW_PARAMS_YEAR); + if (month >= Calendar.JANUARY && month <= Calendar.DECEMBER) { + mMonth = month; + } + mYear = year; // Figure out what day today is final Time today = new Time(Time.getCurrentTimezone()); @@ -369,17 +333,17 @@ class SimpleMonthView extends View { mCalendar.set(Calendar.DAY_OF_MONTH, 1); mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK); - if (params.containsKey(VIEW_PARAMS_WEEK_START)) { - mWeekStart = params.get(VIEW_PARAMS_WEEK_START); + if (isValidDay(weekStart)) { + mWeekStart = weekStart; } else { mWeekStart = mCalendar.getFirstDayOfWeek(); } - if (params.containsKey(VIEW_PARAMS_ENABLEDDAYRANGE_START)) { - mEnabledDayStart = params.get(VIEW_PARAMS_ENABLEDDAYRANGE_START); + if (enabledDayStart > 0 && enabledDayEnd < 32) { + mEnabledDayStart = enabledDayStart; } - if (params.containsKey(VIEW_PARAMS_ENABLEDDAYRANGE_END)) { - mEnabledDayEnd = params.get(VIEW_PARAMS_ENABLEDDAYRANGE_END); + if (enabledDayEnd > 0 && enabledDayEnd < 32 && enabledDayEnd >= enabledDayStart) { + mEnabledDayEnd = enabledDayEnd; } mNumCells = getDaysInMonth(mMonth, mYear); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index fac0eb269a26..52618cc1084d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -657,6 +657,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int shadowcolor = 0; float dx = 0, dy = 0, r = 0; boolean elegant = false; + float letterSpacing = 0; final Resources.Theme theme = context.getTheme(); @@ -737,6 +738,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case com.android.internal.R.styleable.TextAppearance_elegantTextHeight: elegant = appearance.getBoolean(attr, false); break; + + case com.android.internal.R.styleable.TextAppearance_letterSpacing: + letterSpacing = appearance.getFloat(attr, 0); + break; } } @@ -1078,6 +1083,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case com.android.internal.R.styleable.TextView_elegantTextHeight: elegant = a.getBoolean(attr, false); break; + + case com.android.internal.R.styleable.TextView_letterSpacing: + letterSpacing = a.getFloat(attr, 0); + break; } } a.recycle(); @@ -1259,6 +1268,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } setRawTextSize(textSize); setElegantTextHeight(elegant); + setLetterSpacing(letterSpacing); if (allCaps) { setTransformationMethod(new AllCapsTransformationMethod(getContext())); @@ -2487,6 +2497,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener com.android.internal.R.styleable.TextAppearance_elegantTextHeight, false)); } + if (appearance.hasValue(com.android.internal.R.styleable.TextAppearance_letterSpacing)) { + setLetterSpacing(appearance.getFloat( + com.android.internal.R.styleable.TextAppearance_letterSpacing, 0)); + } + appearance.recycle(); } @@ -2667,6 +2682,41 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * @return the extent by which text is currently being letter-spaced. + * This will normally be 0. + * + * @see #setLetterSpacing(float) + * @hide + */ + public float getLetterSpacing() { + return mTextPaint.getLetterSpacing(); + } + + /** + * Sets text letter-spacing. The value is in 'EM' units. Typical values + * for slight expansion will be around 0.05. Negative values tighten text. + * + * @see #getLetterSpacing() + * @see Paint#setFlags + * + * @attr ref android.R.styleable#TextView_letterSpacing + * @hide + */ + @android.view.RemotableViewMethod + public void setLetterSpacing(float letterSpacing) { + if (letterSpacing != mTextPaint.getLetterSpacing()) { + mTextPaint.setLetterSpacing(letterSpacing); + + if (mLayout != null) { + nullLayouts(); + requestLayout(); + invalidate(); + } + } + } + + + /** * Sets the text color for all the states (normal, selected, * focused) to be this color. * diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index 71102e8a3eba..0b15eb60130b 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -17,6 +17,7 @@ package android.widget; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActionBar; import android.content.Context; import android.content.res.TypedArray; @@ -654,27 +655,13 @@ public class Toolbar extends ViewGroup { } /** - * Set the icon to use for the toolbar's navigation button. - * - * <p>The navigation button appears at the start of the toolbar if present. Setting an icon - * will make the navigation button visible.</p> - * - * <p>If you use a navigation icon you should also set a description for its action using - * {@link #setNavigationDescription(int)}. This is used for accessibility and tooltips.</p> - * - * @param resId Resource ID of a drawable to set - */ - public void setNavigationIcon(int resId) { - setNavigationIcon(getContext().getDrawable(resId)); - } - - /** * Retrieve the currently configured content description for the navigation button view. * This will be used to describe the navigation action to users through mechanisms such * as screen readers or tooltips. * * @return The navigation button's content description */ + @Nullable public CharSequence getNavigationContentDescription() { return mNavButtonView != null ? mNavButtonView.getContentDescription() : null; } @@ -684,11 +671,11 @@ public class Toolbar extends ViewGroup { * description will be read via screen readers or other accessibility systems to explain * the action of the navigation button. * - * @param description Content description to set + * @param resId Resource ID of a content description string to set, or 0 to + * clear the description */ - public void setNavigationContentDescription(CharSequence description) { - ensureNavButtonView(); - mNavButtonView.setContentDescription(description); + public void setNavigationContentDescription(int resId) { + setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null); } /** @@ -696,11 +683,32 @@ public class Toolbar extends ViewGroup { * description will be read via screen readers or other accessibility systems to explain * the action of the navigation button. * - * @param resId Resource ID of a content description string to set + * @param description Content description to set, or <code>null</code> to + * clear the content description */ - public void setNavigationContentDescription(int resId) { - ensureNavButtonView(); - mNavButtonView.setContentDescription(resId != 0 ? getContext().getText(resId) : null); + public void setNavigationContentDescription(@Nullable CharSequence description) { + if (!TextUtils.isEmpty(description)) { + ensureNavButtonView(); + } + if (mNavButtonView != null) { + mNavButtonView.setContentDescription(description); + } + } + + /** + * Set the icon to use for the toolbar's navigation button. + * + * <p>The navigation button appears at the start of the toolbar if present. Setting an icon + * will make the navigation button visible.</p> + * + * <p>If you use a navigation icon you should also set a description for its action using + * {@link #setNavigationContentDescription(int)}. This is used for accessibility and + * tooltips.</p> + * + * @param resId Resource ID of a drawable to set + */ + public void setNavigationIcon(int resId) { + setNavigationIcon(getContext().getDrawable(resId)); } /** @@ -710,11 +718,12 @@ public class Toolbar extends ViewGroup { * will make the navigation button visible.</p> * * <p>If you use a navigation icon you should also set a description for its action using - * {@link #setNavigationDescription(int)}. This is used for accessibility and tooltips.</p> + * {@link #setNavigationContentDescription(int)}. This is used for accessibility and + * tooltips.</p> * - * @param icon Drawable to set + * @param icon Drawable to set, may be null to clear the icon */ - public void setNavigationIcon(Drawable icon) { + public void setNavigationIcon(@Nullable Drawable icon) { if (icon != null) { ensureNavButtonView(); if (mNavButtonView.getParent() == null) { @@ -733,40 +742,12 @@ public class Toolbar extends ViewGroup { * * @return The navigation icon drawable */ + @Nullable public Drawable getNavigationIcon() { return mNavButtonView != null ? mNavButtonView.getDrawable() : null; } /** - * Set a description for the navigation button. - * - * <p>This description string is used for accessibility, tooltips and other facilities - * to improve discoverability.</p> - * - * @param resId Resource ID of a string to set - */ - public void setNavigationDescription(int resId) { - setNavigationDescription(getContext().getText(resId)); - } - - /** - * Set a description for the navigation button. - * - * <p>This description string is used for accessibility, tooltips and other facilities - * to improve discoverability.</p> - * - * @param description String to set as the description - */ - public void setNavigationDescription(CharSequence description) { - if (!TextUtils.isEmpty(description)) { - ensureNavButtonView(); - } - if (mNavButtonView != null) { - mNavButtonView.setContentDescription(description); - } - } - - /** * Set a listener to respond to navigation events. * * <p>This listener will be called whenever the user clicks the navigation button diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 9ff2cf42cb98..a52dd484ae31 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -40,8 +40,6 @@ interface IAppOpsService { int checkAudioOperation(int code, int usage, int uid, String packageName); void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages); - void setDeviceOwner(String packageName); - void setProfileOwner(String packageName, int userHandle); void setUserRestrictions(in Bundle restrictions, int userHandle); void removeUser(int userHandle); diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 7d5abd2cca14..22ec4bead91e 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -33,19 +33,24 @@ interface IVoiceInteractionManagerService { void finish(IBinder token); /** - * Lists the registered Sound models for keyphrase detection. + * Lists the registered Sound model for keyphrase detection. * May be null if no matching sound models exist. - * - * @param service The current voice interaction service. */ - List<SoundTrigger.KeyphraseSoundModel> listRegisteredKeyphraseSoundModels( - in IVoiceInteractionService service); + SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId); /** * Updates the given keyphrase sound model. Adds the model if it doesn't exist currently. */ int updateKeyphraseSoundModel(in SoundTrigger.KeyphraseSoundModel model); + /** + * Deletes the given keyphrase sound model. + */ + int deleteKeyphraseSoundModel(int keyphraseId); /** + * Indicates if there's a keyphrase sound model available for the given keyphrase ID. + */ + boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId); + /** * Gets the properties of the DSP hardware on this device, null if not present. */ SoundTrigger.ModuleProperties getDspModuleProperties(in IVoiceInteractionService service); @@ -53,7 +58,7 @@ interface IVoiceInteractionManagerService { * Starts a recognition for the given keyphrase. */ int startRecognition(in IVoiceInteractionService service, int keyphraseId, - in SoundTrigger.KeyphraseSoundModel soundModel, in IRecognitionStatusCallback callback, + in IRecognitionStatusCallback callback, in SoundTrigger.RecognitionConfig recognitionConfig); /** * Stops a recognition for the given keyphrase. diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 0eadde1d735b..1c013530f209 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -89,7 +89,7 @@ public class IntentForwarderActivity extends Activity { Slog.e(TAG, "PackageManagerService is dead?"); } if (canForward) { - newIntent.prepareToLeaveUser(callingUserId); + newIntent.setContentUserHint(callingUserId); final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser( newIntent, MATCH_DEFAULT_ONLY, userDest.getIdentifier()); diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java index 1bcb684c64c5..298dd44557c6 100644 --- a/core/java/com/android/internal/app/ToolbarActionBar.java +++ b/core/java/com/android/internal/app/ToolbarActionBar.java @@ -154,7 +154,7 @@ public class ToolbarActionBar extends ActionBar { @Override public void setHomeActionContentDescription(CharSequence description) { - mToolbar.setNavigationDescription(description); + mToolbar.setNavigationContentDescription(description); } @Override @@ -164,7 +164,7 @@ public class ToolbarActionBar extends ActionBar { @Override public void setHomeActionContentDescription(int resId) { - mToolbar.setNavigationDescription(resId); + mToolbar.setNavigationContentDescription(resId); } @Override diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl index 643225d7f031..36de52b2ed4e 100644 --- a/core/java/com/android/internal/backup/IBackupTransport.aidl +++ b/core/java/com/android/internal/backup/IBackupTransport.aidl @@ -57,6 +57,38 @@ interface IBackupTransport { String currentDestinationString(); /** + * Ask the transport for an Intent that can be used to launch a more detailed + * secondary data management activity. For example, the configuration intent might + * be one for allowing the user to select which account they wish to associate + * their backups with, and the management intent might be one which presents a + * UI for managing the data on the backend. + * + * <p>In the Settings UI, the configuration intent will typically be invoked + * when the user taps on the preferences item labeled with the current + * destination string, and the management intent will be placed in an overflow + * menu labelled with the management label string. + * + * <p>If the transport does not supply any user-facing data management + * UI, then it should return {@code null} from this method. + * + * @return An intent that can be passed to Context.startActivity() in order to + * launch the transport's data-management UI. This method will return + * {@code null} if the transport does not offer any user-facing data + * management UI. + */ + Intent dataManagementIntent(); + + /** + * On demand, supply a short string that can be shown to the user as the label + * on an overflow menu item used to invoked the data management UI. + * + * @return A string to be used as the label for the transport's data management + * affordance. If the transport supplies a data management intent, this + * method must not return {@code null}. + */ + String dataManagementLabel(); + + /** * Ask the transport where, on local device storage, to keep backup state blobs. * This is per-transport so that mock transports used for testing can coexist with * "live" backup services without interfering with the live bookkeeping. The diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java index 50e7bcfb9b22..97e1102d8cac 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/core/java/com/android/internal/backup/LocalTransport.java @@ -64,6 +64,9 @@ public class LocalTransport extends BackupTransport { private static final String TRANSPORT_DESTINATION_STRING = "Backing up to debug-only private cache"; + private static final String TRANSPORT_DATA_MANAGEMENT_LABEL + = ""; + private static final String INCREMENTAL_DIR = "_delta"; private static final String FULL_DATA_DIR = "_full"; @@ -123,6 +126,17 @@ public class LocalTransport extends BackupTransport { return TRANSPORT_DESTINATION_STRING; } + public Intent dataManagementIntent() { + // The local transport does not present a data-management UI + // TODO: consider adding simple UI to wipe the archives entirely, + // for cleaning up the cache partition. + return null; + } + + public String dataManagementLabel() { + return TRANSPORT_DATA_MANAGEMENT_LABEL; + } + @Override public String transportDirName() { return TRANSPORT_DIR_NAME; diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java index fdd24a6b9e66..52485ddb7fa7 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java +++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java @@ -54,8 +54,8 @@ public class InputMethodSubtypeSwitchingController { public final CharSequence mSubtypeName; public final InputMethodInfo mImi; public final int mSubtypeId; - private final boolean mIsSystemLocale; - private final boolean mIsSystemLanguage; + public final boolean mIsSystemLocale; + public final boolean mIsSystemLanguage; public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName, InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) { @@ -68,8 +68,28 @@ public class InputMethodSubtypeSwitchingController { mIsSystemLanguage = false; } else { mIsSystemLocale = subtypeLocale.equals(systemLocale); - mIsSystemLanguage = mIsSystemLocale - || subtypeLocale.startsWith(systemLocale.substring(0, 2)); + if (mIsSystemLocale) { + mIsSystemLanguage = true; + } else { + // TODO: Use Locale#getLanguage or Locale#toLanguageTag + final String systemLanguage = parseLanguageFromLocaleString(systemLocale); + final String subtypeLanguage = parseLanguageFromLocaleString(subtypeLocale); + mIsSystemLanguage = systemLanguage.length() >= 2 && + systemLanguage.equals(subtypeLanguage); + } + } + } + + /** + * Returns the language component of a given locale string. + * TODO: Use {@link Locale#getLanguage()} instead. + */ + private static String parseLanguageFromLocaleString(final String locale) { + final int idx = locale.indexOf('_'); + if (idx < 0) { + return locale; + } else { + return locale.substring(0, idx); } } diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index c552a41cd447..009926921659 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -27,6 +27,7 @@ import android.os.UserHandle; import android.net.RouteInfo; import android.net.LinkAddress; +import java.net.Inet4Address; import java.net.InetAddress; import java.util.List; import java.util.ArrayList; @@ -74,6 +75,17 @@ public class VpnConfig implements Parcelable { public long startTime = -1; public boolean legacy; public boolean blocking; + public boolean allowBypass; + public boolean allowIPv4; + public boolean allowIPv6; + + public void updateAllowedFamilies(InetAddress address) { + if (address instanceof Inet4Address) { + allowIPv4 = true; + } else { + allowIPv6 = true; + } + } public void addLegacyRoutes(String routesStr) { if (routesStr.trim().equals("")) { @@ -86,6 +98,7 @@ public class VpnConfig implements Parcelable { RouteInfo info = new RouteInfo(new LinkAddress (InetAddress.parseNumericAddress(split[0]), Integer.parseInt(split[1])), null); this.routes.add(info); + updateAllowedFamilies(info.getDestination().getAddress()); } } @@ -100,6 +113,7 @@ public class VpnConfig implements Parcelable { LinkAddress addr = new LinkAddress(InetAddress.parseNumericAddress(split[0]), Integer.parseInt(split[1])); this.addresses.add(addr); + updateAllowedFamilies(addr.getAddress()); } } @@ -122,6 +136,9 @@ public class VpnConfig implements Parcelable { out.writeLong(startTime); out.writeInt(legacy ? 1 : 0); out.writeInt(blocking ? 1 : 0); + out.writeInt(allowBypass ? 1 : 0); + out.writeInt(allowIPv4 ? 1 : 0); + out.writeInt(allowIPv6 ? 1 : 0); } public static final Parcelable.Creator<VpnConfig> CREATOR = @@ -141,6 +158,9 @@ public class VpnConfig implements Parcelable { config.startTime = in.readLong(); config.legacy = in.readInt() != 0; config.blocking = in.readInt() != 0; + config.allowBypass = in.readInt() != 0; + config.allowIPv4 = in.readInt() != 0; + config.allowIPv6 = in.readInt() != 0; return config; } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 84bd44315c43..969c0dbee121 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -34,6 +34,7 @@ oneway interface IStatusBar boolean showImeSwitcher); void setHardKeyboardStatus(boolean available, boolean enabled); void setWindowState(int window, int state); + void buzzBeepBlinked(); void showRecentApps(boolean triggeredFromAltTab); void hideRecentApps(boolean triggeredFromAltTab); diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java index c0d1e8843ebd..414b7bc0c407 100644 --- a/core/java/com/android/internal/util/Preconditions.java +++ b/core/java/com/android/internal/util/Preconditions.java @@ -16,6 +16,8 @@ package com.android.internal.util; +import java.util.Collection; + /** * Simple static methods to be called at the start of your own methods to verify * correct arguments and state. @@ -210,7 +212,7 @@ public class Preconditions { } /** - * Ensures that the array is not {@code null}, and none if its elements are {@code null}. + * Ensures that the array is not {@code null}, and none of its elements are {@code null}. * * @param value an array of boxed objects * @param valueName the name of the argument to use if the check fails @@ -235,6 +237,57 @@ public class Preconditions { } /** + * Ensures that the {@link Collection} is not {@code null}, and none of its elements are + * {@code null}. + * + * @param value a {@link Collection} of boxed objects + * @param valueName the name of the argument to use if the check fails + * + * @return the validated {@link Collection} + * + * @throws NullPointerException if the {@code value} or any of its elements were {@code null} + */ + public static <T> Collection<T> checkCollectionElementsNotNull(final Collection<T> value, + final String valueName) { + if (value == null) { + throw new NullPointerException(valueName + " must not be null"); + } + + long ctr = 0; + for (T elem : value) { + if (elem == null) { + throw new NullPointerException( + String.format("%s[%d] must not be null", valueName, ctr)); + } + ++ctr; + } + + return value; + } + + /** + * Ensures that the {@link Collection} is not {@code null}, and contains at least one element. + * + * @param value a {@link Collection} of boxed elements. + * @param valueName the name of the argument to use if the check fails. + + * @return the validated {@link Collection} + * + * @throws NullPointerException if the {@code value} was {@code null} + * @throws IllegalArgumentException if the {@code value} was empty + */ + public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value, + final String valueName) { + if (value == null) { + throw new NullPointerException(valueName + " must not be null"); + } + if (value.isEmpty()) { + throw new IllegalArgumentException(valueName + " is empty"); + } + return value; + } + + /** * Ensures that all elements in the argument floating point array are within the inclusive range * * <p>While this can be used to range check against +/- infinity, note that all NaN numbers diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java index af966b194e56..d9ebc258a8b1 100644 --- a/core/java/com/android/internal/util/Protocol.java +++ b/core/java/com/android/internal/util/Protocol.java @@ -48,6 +48,8 @@ public class Protocol { public static final int BASE_WIFI_CONTROLLER = 0x00026000; public static final int BASE_WIFI_SCANNER = 0x00027000; public static final int BASE_WIFI_SCANNER_SERVICE = 0x00027100; + public static final int BASE_WIFI_RTT_MANAGER = 0x00027200; + public static final int BASE_WIFI_RTT_SERVICE = 0x00027300; public static final int BASE_WIFI_PASSPOINT_MANAGER = 0x00028000; public static final int BASE_WIFI_PASSPOINT_SERVICE = 0x00028100; public static final int BASE_DHCP = 0x00030000; diff --git a/core/jni/android/graphics/Canvas.h b/core/jni/android/graphics/Canvas.h index 3cd57f4d1110..2577a900ae01 100644 --- a/core/jni/android/graphics/Canvas.h +++ b/core/jni/android/graphics/Canvas.h @@ -14,130 +14,6 @@ * limitations under the License. */ -#ifndef ANDROID_GRAPHICS_CANVAS_H -#define ANDROID_GRAPHICS_CANVAS_H - -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkMatrix.h" - -namespace android { - -class Canvas { -public: - virtual ~Canvas() {}; - - static Canvas* create_canvas(SkBitmap* bitmap); - static Canvas* create_canvas(SkCanvas* skiaCanvas); - - // TODO: enable HWUI to either create similar canvas wrapper or subclass - // directly from Canvas - //static Canvas* create_canvas(uirenderer::Renderer* renderer); - - // TODO: this is a temporary affordance until all necessary logic can be - // moved within this interface! Further, the return value should - // NOT be unref'd and is valid until this canvas is destroyed or a - // new bitmap is set. - virtual SkCanvas* getSkCanvas() = 0; - - virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0; - - virtual bool isOpaque() = 0; - virtual int width() = 0; - virtual int height() = 0; - -// ---------------------------------------------------------------------------- -// Canvas state operations -// ---------------------------------------------------------------------------- - // Save (layer) - virtual int getSaveCount() const = 0; - virtual int save(SkCanvas::SaveFlags flags) = 0; - virtual void restore() = 0; - virtual void restoreToCount(int saveCount) = 0; - - virtual int saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, SkCanvas::SaveFlags flags) = 0; - virtual int saveLayerAlpha(float left, float top, float right, float bottom, - int alpha, SkCanvas::SaveFlags flags) = 0; - - // Matrix - virtual void getMatrix(SkMatrix* outMatrix) const = 0; - virtual void setMatrix(const SkMatrix& matrix) = 0; - - virtual void concat(const SkMatrix& matrix) = 0; - virtual void rotate(float degrees) = 0; - virtual void scale(float sx, float sy) = 0; - virtual void skew(float sx, float sy) = 0; - virtual void translate(float dx, float dy) = 0; - - // clip - virtual bool getClipBounds(SkRect* outRect) const = 0; - virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0; - virtual bool quickRejectPath(const SkPath& path) const = 0; - - virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0; - virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0; - virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0; - - // filters - virtual SkDrawFilter* getDrawFilter() = 0; - virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0; - -// ---------------------------------------------------------------------------- -// Canvas draw operations -// ---------------------------------------------------------------------------- - virtual void drawColor(int color, SkXfermode::Mode mode) = 0; - virtual void drawPaint(const SkPaint& paint) = 0; - - // Geometry - virtual void drawPoint(float x, float y, const SkPaint& paint) = 0; - virtual void drawPoints(const float* points, int count, const SkPaint& paint) = 0; - virtual void drawLine(float startX, float startY, float stopX, float stopY, - const SkPaint& paint) = 0; - virtual void drawLines(const float* points, int count, const SkPaint& paint) = 0; - virtual void drawRect(float left, float top, float right, float bottom, - const SkPaint& paint) = 0; - virtual void drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint& paint) = 0; - virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0; - virtual void drawOval(float left, float top, float right, float bottom, - const SkPaint& paint) = 0; - virtual void drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0; - virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0; - virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, - const float* verts, const float* tex, const int* colors, - const uint16_t* indices, int indexCount, const SkPaint& paint) = 0; - - // Bitmap-based - virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, - const SkPaint* paint) = 0; - virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, - const SkPaint* paint) = 0; - virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, - float srcRight, float srcBottom, float dstLeft, float dstTop, - float dstRight, float dstBottom, const SkPaint* paint) = 0; - virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) = 0; - - // Text - virtual void drawText(const uint16_t* text, const float* positions, int count, - const SkPaint& paint, float x, float y, - float boundsLeft, float boundsTop, float boundsRight, float boundsBottom) = 0; - virtual void drawPosText(const uint16_t* text, const float* positions, int count, - int posCount, const SkPaint& paint) = 0; - virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, - float hOffset, float vOffset, const SkPaint& paint) = 0; - - /* - * Specifies if the positions passed to ::drawText are absolute or relative - * to the (x,y) value provided. - * - * If true the (x,y) values are ignored. Otherwise, those (x,y) values need - * to be added to each glyph's position to get its absolute position. - */ - virtual bool drawTextAbsolutePos() const = 0; -}; - -}; // namespace android -#endif // ANDROID_GRAPHICS_CANVAS_H +// This header is shared with other libraries and as such is located in a +// separate directory. +#include <private/graphics/Canvas.h> diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp index c66437a54bce..2ad83305c564 100644 --- a/core/jni/android/graphics/MinikinUtils.cpp +++ b/core/jni/android/graphics/MinikinUtils.cpp @@ -29,6 +29,8 @@ namespace android { // Do an sprintf starting at offset n, abort on overflow +static int snprintfcat(char* buf, int off, int size, const char* format, ...) + __attribute__((__format__(__printf__, 4, 5))); static int snprintfcat(char* buf, int off, int size, const char* format, ...) { va_list args; va_start(args, format); @@ -38,28 +40,29 @@ static int snprintfcat(char* buf, int off, int size, const char* format, ...) { return off + n; } -std::string MinikinUtils::setLayoutProperties(Layout* layout, const Paint* paint, int bidiFlags, - TypefaceImpl* typeface) { +void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface, + const uint16_t* buf, size_t start, size_t count, size_t bufSize) { TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface); layout->setFontCollection(resolvedFace->fFontCollection); FontStyle style = resolvedFace->fStyle; - char css[256]; + char css[512]; int off = snprintfcat(css, 0, sizeof(css), "font-size: %d; font-scale-x: %f; font-skew-x: %f; -paint-flags: %d;" - " font-weight: %d; font-style: %s; -minikin-bidi: %d;", + " font-weight: %d; font-style: %s; -minikin-bidi: %d; letter-spacing: %f;", (int)paint->getTextSize(), paint->getTextScaleX(), paint->getTextSkewX(), MinikinFontSkia::packPaintFlags(paint), style.getWeight() * 100, style.getItalic() ? "italic" : "normal", - bidiFlags); + bidiFlags, + paint->getLetterSpacing()); SkString langString = paint->getPaintOptionsAndroid().getLanguage().getTag(); off = snprintfcat(css, off, sizeof(css), " lang: %s;", langString.c_str()); SkPaintOptionsAndroid::FontVariant var = paint->getPaintOptionsAndroid().getFontVariant(); const char* varstr = var == SkPaintOptionsAndroid::kElegant_Variant ? "elegant" : "compact"; off = snprintfcat(css, off, sizeof(css), " -minikin-variant: %s;", varstr); - return std::string(css); + layout->doLayout(buf, start, count, bufSize, std::string(css)); } float MinikinUtils::xOffsetForTextAlign(Paint* paint, const Layout& layout) { diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h index 0562c3b1d0e2..647cbd8376dd 100644 --- a/core/jni/android/graphics/MinikinUtils.h +++ b/core/jni/android/graphics/MinikinUtils.h @@ -45,8 +45,8 @@ class TypefaceImpl; class MinikinUtils { public: - static std::string setLayoutProperties(Layout* layout, const Paint* paint, int bidiFlags, - TypefaceImpl* typeface); + static void doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface, + const uint16_t* buf, size_t start, size_t count, size_t bufSize); static float xOffsetForTextAlign(Paint* paint, const Layout& layout); diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index c06f0d2bfcd3..a1f09bde12e9 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -423,6 +423,16 @@ public: GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(skewX); } + static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + return paint->getLetterSpacing(); + } + + static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + paint->setLetterSpacing(letterSpacing); + } + static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) { const int kElegantTop = 2500; const int kElegantBottom = -1000; @@ -525,8 +535,7 @@ public: Layout layout; TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint); - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(textArray, index, count, textLength, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, index, count, textLength); result = layout.getAdvance(); env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT); return result; @@ -553,8 +562,7 @@ public: Layout layout; TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint); - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(textArray, start, count, textLength, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, start, count, textLength); width = layout.getAdvance(); env->ReleaseStringChars(text, textArray); @@ -576,8 +584,7 @@ public: Layout layout; TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint); - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(textArray, 0, textLength, textLength, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength); width = layout.getAdvance(); env->ReleaseStringChars(text, textArray); @@ -606,8 +613,7 @@ public: jfloat* widthsArray = autoWidths.ptr(); Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(text, 0, count, count, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count); layout.getAdvances(widthsArray); return count; @@ -660,8 +666,7 @@ public: int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(text, start, count, contextCount, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount); layout.getAdvances(advancesArray); totalAdvance = layout.getAdvance(); @@ -760,8 +765,7 @@ public: static void getTextPath(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar* text, jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) { Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(text, 0, count, count, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count); size_t nGlyphs = layout.nGlyphs(); uint16_t* glyphs = new uint16_t[nGlyphs]; SkPoint* pos = new SkPoint[nGlyphs]; @@ -823,8 +827,7 @@ public: float measured = 0; Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface); - layout.doLayout(text, 0, count, count, css); + MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count); float* advances = new float[count]; layout.getAdvances(advances); const bool forwardScan = (textBufferDirection == Paint::kForward_TextBufferDirection); @@ -904,8 +907,7 @@ public: SkIRect ir; Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface); - layout.doLayout(text, 0, count, count, css); + MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count); MinikinRect rect; layout.getBounds(&rect); r.fLeft = rect.mLeft; @@ -988,6 +990,8 @@ static JNINativeMethod methods[] = { {"setTextScaleX","(F)V", (void*) PaintGlue::setTextScaleX}, {"getTextSkewX","()F", (void*) PaintGlue::getTextSkewX}, {"setTextSkewX","(F)V", (void*) PaintGlue::setTextSkewX}, + {"native_getLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing}, + {"native_setLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing}, {"ascent","()F", (void*) PaintGlue::ascent}, {"descent","()F", (void*) PaintGlue::descent}, {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics}, diff --git a/core/jni/android/graphics/Paint.h b/core/jni/android/graphics/Paint.h index 239b217ef7be..7235cc450959 100644 --- a/core/jni/android/graphics/Paint.h +++ b/core/jni/android/graphics/Paint.h @@ -34,7 +34,16 @@ public: return !(a == b); } + void setLetterSpacing(float letterSpacing) { + mLetterSpacing = letterSpacing; + } + + float getLetterSpacing() const { + return mLetterSpacing; + } + private: + float mLetterSpacing; }; } // namespace android diff --git a/core/jni/android/graphics/PaintImpl.cpp b/core/jni/android/graphics/PaintImpl.cpp index 6baae7607375..ff2bbc514ad8 100644 --- a/core/jni/android/graphics/PaintImpl.cpp +++ b/core/jni/android/graphics/PaintImpl.cpp @@ -22,10 +22,12 @@ namespace android { -Paint::Paint() : SkPaint() { +Paint::Paint() : SkPaint(), + mLetterSpacing(0) { } -Paint::Paint(const Paint& paint) : SkPaint(paint) { +Paint::Paint(const Paint& paint) : SkPaint(paint), + mLetterSpacing(0) { } Paint::~Paint() { @@ -33,11 +35,13 @@ Paint::~Paint() { Paint& Paint::operator=(const Paint& other) { SkPaint::operator=(other); + mLetterSpacing = other.mLetterSpacing; return *this; } bool operator==(const Paint& a, const Paint& b) { - return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b); + return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) + && a.mLetterSpacing == b.mLetterSpacing; } } diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h deleted file mode 100644 index d58c692c1392..000000000000 --- a/core/jni/android/graphics/TextLayout.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "jni.h" - -#include "SkCanvas.h" -#include "SkPaint.h" -#include "unicode/utypes.h" - -#include "TextLayoutCache.h" - -namespace android { - -#define UNICODE_NOT_A_CHAR 0xffff -#define UNICODE_ZWSP 0x200b -#define UNICODE_FIRST_LOW_SURROGATE 0xdc00 -#define UNICODE_FIRST_HIGH_SURROGATE 0xd800 -#define UNICODE_FIRST_PRIVATE_USE 0xe000 -#define UNICODE_FIRST_RTL_CHAR 0x0590 - -/* - * Temporary buffer size - */ -#define CHAR_BUFFER_SIZE 80 - -/** - * Turn on for using the Cache - */ -#define USE_TEXT_LAYOUT_CACHE 1 - -enum { - kBidi_LTR = 0, - kBidi_RTL = 1, - kBidi_Default_LTR = 2, - kBidi_Default_RTL = 3, - kBidi_Force_LTR = 4, - kBidi_Force_RTL = 5, - - kBidi_Mask = 0x7 -}; - -enum { - kDirection_LTR = 0, - kDirection_RTL = 1, - - kDirection_Mask = 0x1 -}; - -class TextLayout { -public: - - static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start, - jint count, jint contextCount, jint dirFlags, - jfloat* resultAdvances, jfloat* resultTotalAdvance); - - static void getTextPath(SkPaint* paint, const jchar* text, jsize len, - jint bidiFlags, jfloat x, jfloat y, SkPath* path); - - static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len, - int bidiFlags, jfloat hOffset, jfloat vOffset, - SkPath* path, SkCanvas* canvas); - -private: - static bool needsLayout(const jchar* text, jint len, jint bidiFlags); - - static void handleText(SkPaint* paint, const jchar* text, jsize len, - int bidiFlags, jfloat x, jfloat y, SkPath* path); -}; -} // namespace android diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 000791275488..a9b01d0926de 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -486,8 +486,7 @@ void drawText(Canvas* canvas, const uint16_t* text, int start, int count, int co Paint paint(origPaint); Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface); - layout.doLayout(text, start, count, contextCount, css); + MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount); size_t nGlyphs = layout.nGlyphs(); uint16_t* glyphs = new uint16_t[nGlyphs]; @@ -625,8 +624,7 @@ static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int const Paint& paint, TypefaceImpl* typeface) { Paint paintCopy(paint); Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, &paintCopy, bidiFlags, typeface); - layout.doLayout(text, 0, count, count, css); + MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count); hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); // Set align to left for drawing, as we don't want individual diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index 3a3328f75230..eaadfb205c74 100644 --- a/core/jni/android_hardware_camera2_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -1173,8 +1173,8 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt calibrationTransform1[ctr++] = entry1.data.r[i].denominator; } - BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, calibrationTransform1, - TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer); + BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, + calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer); if (!singleIlluminant) { camera_metadata_entry entry2 = @@ -1188,8 +1188,8 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt calibrationTransform2[ctr++] = entry2.data.r[i].denominator; } - BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, calibrationTransform1, - TIFF_IFD_0), env, TAG_CAMERACALIBRATION2, writer); + BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, + calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION2, writer); } } @@ -1294,6 +1294,21 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt } { + // Setup sensor noise model + camera_metadata_entry entry = + results.find(ANDROID_SENSOR_NOISE_PROFILE); + + if (entry.count > 0) { + BAIL_IF_INVALID(writer->addEntry(TAG_NOISEPROFILE, entry.count, + entry.data.d, TIFF_IFD_0), env, + TAG_NOISEPROFILE, writer); + } else { + ALOGW("%s: No noise profile found in result metadata. Image quality may be reduced.", + __FUNCTION__); + } + } + + { // Setup opcode List 2 camera_metadata_entry entry1 = characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE); diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index d2f5b5d6d633..697cdc686514 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -587,7 +587,7 @@ static jint LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv* env, jobject int32_t transform = 0; - if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != OK) { + if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != NO_ERROR) { ALOGE("%s: Invalid rotation transform %s (%d)", __FUNCTION__, strerror(-err), err); return err; @@ -595,7 +595,7 @@ static jint LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv* env, jobject ALOGV("%s: Setting buffer sticky transform to %d", __FUNCTION__, transform); - if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != OK) { + if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != NO_ERROR) { ALOGE("%s: Unable to configure surface transform, error %s (%d)", __FUNCTION__, strerror(-err), err); return err; @@ -604,6 +604,26 @@ static jint LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv* env, jobject return NO_ERROR; } +static jint LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv* env, jobject thiz, jobject surface, + jlong timestamp) { + ALOGV("nativeSetNextTimestamp"); + sp<ANativeWindow> anw; + if ((anw = getNativeWindow(env, surface)) == NULL) { + ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); + return BAD_VALUE; + } + + status_t err = NO_ERROR; + + if ((err = native_window_set_buffers_timestamp(anw.get(), static_cast<int64_t>(timestamp))) != + NO_ERROR) { + ALOGE("%s: Unable to set surface timestamp, error %s (%d)", __FUNCTION__, strerror(-err), + err); + return err; + } + return NO_ERROR; +} + } // extern "C" static JNINativeMethod gCameraDeviceMethods[] = { @@ -634,6 +654,9 @@ static JNINativeMethod gCameraDeviceMethods[] = { { "nativeSetSurfaceOrientation", "(Landroid/view/Surface;II)I", (void *)LegacyCameraDevice_nativeSetSurfaceOrientation }, + { "nativeSetNextTimestamp", + "(Landroid/view/Surface;J)I", + (void *)LegacyCameraDevice_nativeSetNextTimestamp }, }; // Get all the required offsets in java class and register native functions diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index c8812fc2ddd8..09c5f3ab830e 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -35,14 +35,20 @@ using namespace android; // ---------------------------------------------------------------------------- static const char* const kClassPathName = "android/media/AudioRecord"; +static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes"; -struct fields_t { +struct audio_record_fields_t { // these fields provide access from C++ to the... jmethodID postNativeEventInJava; //... event post callback method jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data }; -static fields_t javaAudioRecordFields; +struct audio_attributes_fields_t { + jfieldID fieldRecSource; // AudioAttributes.mSource + jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags +}; +static audio_attributes_fields_t javaAudioAttrFields; +static audio_record_fields_t javaAudioRecordFields; struct audiorecord_callback_cookie { jclass audioRecord_class; @@ -138,7 +144,7 @@ static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioR // ---------------------------------------------------------------------------- static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jint source, jint sampleRateInHertz, jint channelMask, + jobject jaa, jint sampleRateInHertz, jint channelMask, // Java channel masks map directly to the native definition jint audioFormat, jint buffSizeInBytes, jintArray jSession) { @@ -146,6 +152,11 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d", // sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes); + if (jaa == 0) { + ALOGE("Error creating AudioRecord: invalid audio attributes"); + return (jint) AUDIO_JAVA_ERROR; + } + if (!audio_is_input_channel(channelMask)) { ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask); return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK; @@ -168,11 +179,6 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, size_t frameSize = channelCount * bytesPerSample; size_t frameCount = buffSizeInBytes / frameSize; - if ((uint32_t(source) >= AUDIO_SOURCE_CNT) && (uint32_t(source) != AUDIO_SOURCE_HOTWORD)) { - ALOGE("Error creating AudioRecord: unknown source %d.", source); - return (jint) AUDIORECORD_ERROR_SETUP_INVALIDSOURCE; - } - jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { ALOGE("Can't find %s when setting up callback.", kClassPathName); @@ -196,6 +202,19 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, // create an uninitialized AudioRecord object sp<AudioRecord> lpRecorder = new AudioRecord(); + audio_attributes_t *paa = NULL; + // read the AudioAttributes values + paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); + const jstring jtags = + (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags); + const char* tags = env->GetStringUTFChars(jtags, NULL); + // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it + strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1); + env->ReleaseStringUTFChars(jtags, tags); + paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource); + + ALOGV("AudioRecord_setup for source=%d tags=%s", paa->source, paa->tags); + // create the callback information: // this data will be passed with every AudioRecord callback audiorecord_callback_cookie *lpCallbackData = new audiorecord_callback_cookie; @@ -204,7 +223,7 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this); lpCallbackData->busy = false; - const status_t status = lpRecorder->set((audio_source_t) source, + const status_t status = lpRecorder->set(paa->source, sampleRateInHertz, format, // word length, PCM channelMask, @@ -545,7 +564,7 @@ static JNINativeMethod gMethods[] = { // name, signature, funcPtr {"native_start", "(II)I", (void *)android_media_AudioRecord_start}, {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, - {"native_setup", "(Ljava/lang/Object;IIIII[I)I", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIII[I)I", (void *)android_media_AudioRecord_setup}, {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, {"native_release", "()V", (void *)android_media_AudioRecord_release}, @@ -611,6 +630,23 @@ int register_android_media_AudioRecord(JNIEnv *env) return -1; } + // Get the AudioAttributes class and fields + jclass audioAttrClass = env->FindClass(kAudioAttributesClassPathName); + if (audioAttrClass == NULL) { + ALOGE("Can't find %s", kAudioAttributesClassPathName); + return -1; + } + jclass audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass); + javaAudioAttrFields.fieldRecSource = env->GetFieldID(audioAttributesClassRef, "mSource", "I"); + javaAudioAttrFields.fieldFormattedTags = + env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;"); + env->DeleteGlobalRef(audioAttributesClassRef); + if (javaAudioAttrFields.fieldRecSource == NULL + || javaAudioAttrFields.fieldFormattedTags == NULL) { + ALOGE("Can't initialize AudioAttributes fields"); + return -1; + } + return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 7e2448e4e752..ab38864301f3 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -50,10 +50,10 @@ struct audio_track_fields_t { jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object }; struct audio_attributes_fields_t { - jfieldID fieldUsage; // AudioAttributes.mUsage - jfieldID fieldContentType; // AudioAttributes.mContentType - jfieldID fieldFlags; // AudioAttributes.mFlags - jfieldID fieldTags; // AudioAttributes.mTags + jfieldID fieldUsage; // AudioAttributes.mUsage + jfieldID fieldContentType; // AudioAttributes.mContentType + jfieldID fieldFlags; // AudioAttributes.mFlags + jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags }; static audio_track_fields_t javaAudioTrackFields; static audio_attributes_fields_t javaAudioAttrFields; @@ -263,7 +263,8 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, audio_attributes_t *paa = NULL; // read the AudioAttributes values paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); - const jstring jtags = (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldTags); + const jstring jtags = + (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags); const char* tags = env->GetStringUTFChars(jtags, NULL); // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1); @@ -290,7 +291,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, case MODE_STREAM: status = lpTrack->set( - AUDIO_STREAM_DEFAULT,// stream type + AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) sampleRateInHertz, format,// word length, PCM nativeChannelMask, @@ -301,7 +302,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, 0,// shared mem true,// thread can call Java sessionId,// audio session ID - AudioTrack::TRANSFER_DEFAULT, // default transfer mode + AudioTrack::TRANSFER_SYNC, NULL, // default offloadInfo -1, -1, // default uid, pid values paa); @@ -316,7 +317,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, } status = lpTrack->set( - AUDIO_STREAM_DEFAULT,// stream type + AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) sampleRateInHertz, format,// word length, PCM nativeChannelMask, @@ -327,7 +328,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, lpJniStorage->mMemBase,// shared mem true,// thread can call Java sessionId,// audio session ID - AudioTrack::TRANSFER_DEFAULT, // default transfer mode + AudioTrack::TRANSFER_SHARED, NULL, // default offloadInfo -1, -1, // default uid, pid values paa); @@ -1112,11 +1113,12 @@ int register_android_media_AudioTrack(JNIEnv *env) javaAudioAttrFields.fieldContentType = env->GetFieldID(audioAttributesClassRef, "mContentType", "I"); javaAudioAttrFields.fieldFlags = env->GetFieldID(audioAttributesClassRef, "mFlags", "I"); - javaAudioAttrFields.fieldTags = env->GetFieldID(audioAttributesClassRef, "mFormattedTags", - "Ljava/lang/String;"); + javaAudioAttrFields.fieldFormattedTags = + env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;"); env->DeleteGlobalRef(audioAttributesClassRef); if (javaAudioAttrFields.fieldUsage == NULL || javaAudioAttrFields.fieldContentType == NULL - || javaAudioAttrFields.fieldFlags == NULL || javaAudioAttrFields.fieldTags == NULL) { + || javaAudioAttrFields.fieldFlags == NULL + || javaAudioAttrFields.fieldFormattedTags == NULL) { ALOGE("Can't initialize AudioAttributes fields"); return -1; } diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index 50f6c73fa0da..44863cc7ef4c 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -187,6 +187,45 @@ static void android_os_Parcel_writeNative(JNIEnv* env, jclass clazz, jlong nativ } } +static void android_os_Parcel_writeBlob(JNIEnv* env, jclass clazz, jlong nativePtr, jobject data, + jint offset, jint length) { + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel == NULL) { + return; + } + + if (data == NULL) { + const status_t err = parcel->writeInt32(-1); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + return; + } + + const status_t err = parcel->writeInt32(length); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + return; + } + + android::Parcel::WritableBlob blob; + android::status_t err2 = parcel->writeBlob(length, &blob); + if (err2 != NO_ERROR) { + signalExceptionForError(env, clazz, err2); + return; + } + + jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0); + if (ar == NULL) { + memset(blob.data(), 0, length); + } else { + memcpy(blob.data(), ar + offset, length); + env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0); + } + + blob.release(); +} + static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); const status_t err = parcel->writeInt32(val); @@ -297,6 +336,36 @@ static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, j return ret; } +static jbyteArray android_os_Parcel_readBlob(JNIEnv* env, jclass clazz, jlong nativePtr) +{ + jbyteArray ret = NULL; + + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + int32_t len = parcel->readInt32(); + if (len >= 0) { + android::Parcel::ReadableBlob blob; + android::status_t err = parcel->readBlob(len, &blob); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + return NULL; + } + + ret = env->NewByteArray(len); + if (ret != NULL) { + jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0); + if (a2) { + memcpy(a2, blob.data(), len); + env->ReleasePrimitiveArrayCritical(ret, a2, 0); + } + } + blob.release(); + } + } + + return ret; +} + static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); @@ -634,6 +703,7 @@ static const JNINativeMethod gParcelMethods[] = { {"nativeRestoreAllowFds", "(JZ)V", (void*)android_os_Parcel_restoreAllowFds}, {"nativeWriteByteArray", "(J[BII)V", (void*)android_os_Parcel_writeNative}, + {"nativeWriteBlob", "(J[BII)V", (void*)android_os_Parcel_writeBlob}, {"nativeWriteInt", "(JI)V", (void*)android_os_Parcel_writeInt}, {"nativeWriteLong", "(JJ)V", (void*)android_os_Parcel_writeLong}, {"nativeWriteFloat", "(JF)V", (void*)android_os_Parcel_writeFloat}, @@ -643,6 +713,7 @@ static const JNINativeMethod gParcelMethods[] = { {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor}, {"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray}, + {"nativeReadBlob", "(J)[B", (void*)android_os_Parcel_readBlob}, {"nativeReadInt", "(J)I", (void*)android_os_Parcel_readInt}, {"nativeReadLong", "(J)J", (void*)android_os_Parcel_readLong}, {"nativeReadFloat", "(J)F", (void*)android_os_Parcel_readFloat}, diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 0a259aa21cc3..3cd031e870ca 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -620,8 +620,7 @@ static void renderTextLayout(DisplayListRenderer* renderer, Layout* layout, static void renderText(DisplayListRenderer* renderer, const jchar* text, int count, jfloat x, jfloat y, int bidiFlags, Paint* paint, TypefaceImpl* typeface) { Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(text, 0, count, count, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count); x += MinikinUtils::xOffsetForTextAlign(paint, layout); renderTextLayout(renderer, &layout, x, y, paint); } @@ -655,8 +654,7 @@ static void renderTextOnPath(DisplayListRenderer* renderer, const jchar* text, i SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, Paint* paint, TypefaceImpl* typeface) { Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(text, 0, count, count, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count); hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path); Paint::Align align = paint->getTextAlign(); paint->setTextAlign(Paint::kLeft_Align); @@ -670,8 +668,7 @@ static void renderTextRun(DisplayListRenderer* renderer, const jchar* text, jint start, jint count, jint contextCount, jfloat x, jfloat y, int bidiFlags, Paint* paint, TypefaceImpl* typeface) { Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); - layout.doLayout(text, start, count, contextCount, css); + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount); x += MinikinUtils::xOffsetForTextAlign(paint, layout); renderTextLayout(renderer, &layout, x, y, paint); } diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 1f3909af48e8..3b6f0eb40da4 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -117,6 +117,17 @@ static jboolean android_view_RenderNode_setClipToBounds(JNIEnv* env, return SET_AND_DIRTY(setClipToBounds, clipToBounds, RenderNode::GENERIC); } +static jboolean android_view_RenderNode_setClipBounds(JNIEnv* env, + jobject clazz, jlong renderNodePtr, jint left, jint top, jint right, jint bottom) { + android::uirenderer::Rect clipBounds(left, top, right, bottom); + return SET_AND_DIRTY(setClipBounds, clipBounds, RenderNode::GENERIC); +} + +static jboolean android_view_RenderNode_setClipBoundsEmpty(JNIEnv* env, + jobject clazz, jlong renderNodePtr) { + return SET_AND_DIRTY(setClipBoundsEmpty,, RenderNode::GENERIC); +} + static jboolean android_view_RenderNode_setProjectBackwards(JNIEnv* env, jobject clazz, jlong renderNodePtr, jboolean shouldProject) { return SET_AND_DIRTY(setProjectBackwards, shouldProject, RenderNode::GENERIC); @@ -282,12 +293,12 @@ static jboolean android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env, } static jboolean android_view_RenderNode_offsetLeftAndRight(JNIEnv* env, - jobject clazz, jlong renderNodePtr, float offset) { + jobject clazz, jlong renderNodePtr, jint offset) { return SET_AND_DIRTY(offsetLeftRight, offset, RenderNode::X); } static jboolean android_view_RenderNode_offsetTopAndBottom(JNIEnv* env, - jobject clazz, jlong renderNodePtr, float offset) { + jobject clazz, jlong renderNodePtr, jint offset) { return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y); } @@ -313,30 +324,6 @@ static jfloat android_view_RenderNode_getAlpha(JNIEnv* env, return renderNode->stagingProperties().getAlpha(); } -static jfloat android_view_RenderNode_getLeft(JNIEnv* env, - jobject clazz, jlong renderNodePtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - return renderNode->stagingProperties().getLeft(); -} - -static jfloat android_view_RenderNode_getTop(JNIEnv* env, - jobject clazz, jlong renderNodePtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - return renderNode->stagingProperties().getTop(); -} - -static jfloat android_view_RenderNode_getRight(JNIEnv* env, - jobject clazz, jlong renderNodePtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - return renderNode->stagingProperties().getRight(); -} - -static jfloat android_view_RenderNode_getBottom(JNIEnv* env, - jobject clazz, jlong renderNodePtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - return renderNode->stagingProperties().getBottom(); -} - static jfloat android_view_RenderNode_getCameraDistance(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); @@ -488,6 +475,8 @@ static JNINativeMethod gMethods[] = { { "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix }, { "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix }, { "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds }, + { "nSetClipBounds", "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds }, + { "nSetClipBoundsEmpty", "(J)Z", (void*) android_view_RenderNode_setClipBoundsEmpty }, { "nSetProjectBackwards", "(JZ)Z", (void*) android_view_RenderNode_setProjectBackwards }, { "nSetProjectionReceiver","(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver }, @@ -518,16 +507,12 @@ static JNINativeMethod gMethods[] = { { "nSetRight", "(JI)Z", (void*) android_view_RenderNode_setRight }, { "nSetBottom", "(JI)Z", (void*) android_view_RenderNode_setBottom }, { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom }, - { "nOffsetLeftAndRight", "(JF)Z", (void*) android_view_RenderNode_offsetLeftAndRight }, - { "nOffsetTopAndBottom", "(JF)Z", (void*) android_view_RenderNode_offsetTopAndBottom }, + { "nOffsetLeftAndRight", "(JI)Z", (void*) android_view_RenderNode_offsetLeftAndRight }, + { "nOffsetTopAndBottom", "(JI)Z", (void*) android_view_RenderNode_offsetTopAndBottom }, { "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering }, { "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline }, { "nGetAlpha", "(J)F", (void*) android_view_RenderNode_getAlpha }, - { "nGetLeft", "(J)F", (void*) android_view_RenderNode_getLeft }, - { "nGetTop", "(J)F", (void*) android_view_RenderNode_getTop }, - { "nGetRight", "(J)F", (void*) android_view_RenderNode_getRight }, - { "nGetBottom", "(J)F", (void*) android_view_RenderNode_getBottom }, { "nGetCameraDistance", "(J)F", (void*) android_view_RenderNode_getCameraDistance }, { "nGetScaleX", "(J)F", (void*) android_view_RenderNode_getScaleX }, { "nGetScaleY", "(J)F", (void*) android_view_RenderNode_getScaleY }, diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 988d461d0598..d183d8eb2eb3 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -219,9 +219,11 @@ static void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject claz static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr, jint width, jint height, - jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) { + jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius, + jint ambientShadowAlpha, jint spotShadowAlpha) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - proxy->setup(width, height, Vector3(lightX, lightY, lightZ), lightRadius); + proxy->setup(width, height, (Vector3){lightX, lightY, lightZ}, lightRadius, + ambientShadowAlpha, spotShadowAlpha); } static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz, @@ -358,7 +360,7 @@ static JNINativeMethod gMethods[] = { { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize }, { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface }, { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface }, - { "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup }, + { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup }, { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque }, { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 056d470034fd..6a7501dd9232 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2798,6 +2798,13 @@ android:description="@string/permdesc_createMediaProjection" android:protectionLevel="signature" /> + <!-- @SystemApi Allows an application to read install sessions + @hide This is not a third-party API (intended for system apps). --> + <permission android:name="android.permission.READ_INSTALL_SESSIONS" + android:label="@string/permlab_readInstallSessions" + android:description="@string/permdesc_readInstallSessions" + android:protectionLevel="signature|system" /> + <!-- The system process is explicitly the only one allowed to launch the confirmation UI for full backup/restore --> <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/> @@ -3016,6 +3023,11 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> + <service android:name="com.android.server.backup.FullBackupJob" + android:exported="true" + android:permission="android.permission.BIND_JOB_SERVICE" > + </service> + <service android:name="com.android.server.pm.BackgroundDexOptService" android:exported="true" diff --git a/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png Binary files differindex f0910d896404..6c36eae2f4ae 100644 --- a/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png +++ b/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png diff --git a/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png Binary files differindex a0501b38f22f..f7382d373da3 100644 --- a/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png +++ b/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png diff --git a/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png Binary files differindex cac32b5ef7e5..f7382d373da3 100644 --- a/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png +++ b/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png diff --git a/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png Binary files differindex e196bbee20f7..667435189e05 100644 --- a/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png +++ b/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png diff --git a/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png Binary files differindex c5de7683c146..0fb57b2ea21f 100644 --- a/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png +++ b/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png diff --git a/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png Binary files differindex 9137fea85ee4..0fb57b2ea21f 100644 --- a/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png +++ b/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml index d1e2df3f94e1..fb528301fe19 100644 --- a/core/res/res/drawable-nodpi/platlogo.xml +++ b/core/res/res/drawable-nodpi/platlogo.xml @@ -13,27 +13,28 @@ limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size android:width="400dp" android:height="400dp"/> - - <viewport android:viewportHeight="25" android:viewportWidth="25" /> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="400dp" + android:height="400dp" + android:viewportHeight="25" + android:viewportWidth="25" > <path android:name="torso" android:pathData="m2,2 l21,0 l0,21 l-21,0 z" - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" /> <path android:name="|" android:pathData="m4,4 l8,0 l0,17 l-8,0 z" - android:fill="#FF0000FF" + android:fillColor="#FF0000FF" /> <path android:name="_" android:pathData="m5,14 l16,0 l0,6 l-16,0 z" - android:fill="#FFFF0000" + android:fillColor="#FFFF0000" /> </vector> diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml index 6b3be4a181ad..1fee2df3af4b 100644 --- a/core/res/res/drawable-nodpi/stat_sys_adb.xml +++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml @@ -13,10 +13,11 @@ limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size android:width="25dp" android:height="25dp"/> - - <viewport android:viewportHeight="25" android:viewportWidth="25" /> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="25dp" + android:height="25dp" + android:viewportHeight="25" + android:viewportWidth="25" > <path android:name="L-card" @@ -34,7 +35,7 @@ M15,2 l3,0 l0,5 l5,0 l0,3 l-8,0 z" - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" /> diff --git a/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png Binary files differindex 4385b2bec2b2..27bdcb79e3f2 100644 --- a/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png +++ b/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png diff --git a/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png Binary files differindex 4602b35f17e1..05cfab7eef5d 100644 --- a/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png +++ b/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png diff --git a/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png Binary files differindex 513ee8ba7910..05cfab7eef5d 100644 --- a/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png +++ b/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png diff --git a/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png Binary files differindex ca15853f073e..c2d6a542cdc3 100644 --- a/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png +++ b/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png diff --git a/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png Binary files differindex cb295a3f1a3d..6f60bd3c2b7b 100644 --- a/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png +++ b/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png Binary files differindex 81b13aa55567..6f60bd3c2b7b 100644 --- a/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png +++ b/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png diff --git a/core/res/res/drawable-xxxhdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-xxxhdpi/ic_ab_back_mtrl_am_alpha.png Binary files differnew file mode 100644 index 000000000000..70c204021088 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/ic_ab_back_mtrl_am_alpha.png diff --git a/core/res/res/drawable-xxxhdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/ic_menu_search_mtrl_alpha.png Binary files differnew file mode 100644 index 000000000000..2a28f0f04ad9 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/ic_menu_search_mtrl_alpha.png diff --git a/core/res/res/drawable-xxxhdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/ic_search_api_mtrl_alpha.png Binary files differnew file mode 100644 index 000000000000..c873e9b0c807 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/ic_search_api_mtrl_alpha.png diff --git a/core/res/res/drawable/btn_radio_material_anim.xml b/core/res/res/drawable/btn_radio_material_anim.xml index 0be590eb3f53..121e5447798e 100644 --- a/core/res/res/drawable/btn_radio_material_anim.xml +++ b/core/res/res/drawable/btn_radio_material_anim.xml @@ -16,42 +16,52 @@ <animated-selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:state_checked="true"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" /> + <bitmap + android:src="@drawable/btn_radio_to_on_mtrl_015" + android:tint="?attr/colorControlActivated" + android:alpha="?attr/disabledAlpha" /> </item> <item android:state_enabled="false"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" /> + <bitmap + android:src="@drawable/btn_radio_to_on_mtrl_000" + android:tint="?attr/colorControlNormal" + android:alpha="?attr/disabledAlpha" /> </item> <item android:state_checked="true" android:id="@+id/on"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" /> + <bitmap + android:src="@drawable/btn_radio_to_on_mtrl_015" + android:tint="?attr/colorControlActivated" /> </item> <item android:id="@+id/off"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" /> + <bitmap + android:src="@drawable/btn_radio_to_on_mtrl_000" + android:tint="?attr/colorControlNormal" /> </item> <transition android:fromId="@+id/off" android:toId="@+id/on"> <animation-list> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008" android:tint="?attr/colorControlActivated" /> @@ -106,28 +116,28 @@ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014" android:tint="?attr/colorControlNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015" android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015" android:tint="?attr/colorControlNormal" /> </item> </animation-list> </transition> diff --git a/core/res/res/drawable/ic_audio_ring_notif.xml b/core/res/res/drawable/ic_audio_ring_notif.xml index b52db5c33205..60a98abf7f91 100644 --- a/core/res/res/drawable/ic_audio_ring_notif.xml +++ b/core/res/res/drawable/ic_audio_ring_notif.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" - android:height="32dp"/> - - <viewport + android:height="32dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#8A000000" + android:fillColor="#8A000000" android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/> </vector> diff --git a/core/res/res/drawable/ic_audio_ring_notif_mute.xml b/core/res/res/drawable/ic_audio_ring_notif_mute.xml index 8d7d6cbe0747..17dfa7e72c56 100644 --- a/core/res/res/drawable/ic_audio_ring_notif_mute.xml +++ b/core/res/res/drawable/ic_audio_ring_notif_mute.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" - android:height="32dp"/> - - <viewport + android:height="32dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#8A000000" + android:fillColor="#8A000000" android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" /> </vector> diff --git a/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml index 2f1d940eb1a2..2ed33eab4848 100644 --- a/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml +++ b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" - android:height="32dp"/> - - <viewport + android:height="32dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#8A000000" + android:fillColor="#8A000000" android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/> </vector> diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml index 16c101b15c19..e185fc45e0b2 100644 --- a/core/res/res/drawable/ic_corp_badge.xml +++ b/core/res/res/drawable/ic_corp_badge.xml @@ -13,31 +13,28 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20.0dp" - android:height="20.0dp"/> - - <viewport + android:height="20.0dp" android:viewportWidth="20.0" - android:viewportHeight="20.0"/> + android:viewportHeight="20.0"> <path android:pathData="M10.0,10.0m-10.0,0.0a10.0,10.0 0.0,1.0 1.0,20.0 0.0a10.0,10.0 0.0,1.0 1.0,-20.0 0.0" - android:fill="#FF5722"/> + android:fillColor="#FF5722"/> <path android:pathData="M11.139,12.149l-0.001,0.0L8.996,12.149l0.0,-0.571L4.738,11.578l-0.002,2.198c0.0,0.589 0.477,1.066 1.066,1.066l8.535,0.0c0.589,0.0 1.066,-0.477 1.066,-1.066l0.0,-2.198l-4.264,0.0L11.139,12.149z" - android:fill="#FFFFFF"/> + android:fillColor="#FFFFFF"/> <path android:pathData="M8.996,10.006l2.143,0.0l0.0,0.52l4.442,0.0L15.580999,7.909c0.0,-0.589 -0.477,-1.066 -1.066,-1.066l-1.877,0.0L7.544,6.843L5.606,6.843c-0.589,0.0 -1.061,0.477 -1.061,1.066l-0.003,2.617l4.453,0.0L8.996,10.006L8.996,10.006z" - android:fill="#FFFFFF"/> + android:fillColor="#FFFFFF"/> <path android:pathData="M3.367,3.456 h13.016 v13.016 h-13.016z" - android:fill="#00000000"/> + android:fillColor="#00000000"/> <path android:pathData="M7.368,5.263l5.263,0.0l0.0,1.053l-5.263,0.0z" - android:fill="#FFFFFF"/> + android:fillColor="#FFFFFF"/> <path android:pathData="M8.996,12.149l2.1419992,0.0 0.0010004044,0.0 0.0,-0.5699997 -2.1429996,0.0z" - android:fill="#00000000"/> + android:fillColor="#00000000"/> </vector> diff --git a/core/res/res/drawable/ic_corp_icon_badge.xml b/core/res/res/drawable/ic_corp_icon_badge.xml index c8e49e1d5fa5..d20c43133c56 100644 --- a/core/res/res/drawable/ic_corp_icon_badge.xml +++ b/core/res/res/drawable/ic_corp_icon_badge.xml @@ -13,42 +13,39 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64.0dp" - android:height="64.0dp"/> - - <viewport + android:height="64.0dp" android:viewportWidth="64.0" - android:viewportHeight="64.0"/> + android:viewportHeight="64.0"> <path - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="M49.062,50.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0" android:fillOpacity="0.2"/> <path - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="M49.0,49.5m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0" android:fillOpacity="0.2"/> <path android:pathData="M49.0,49.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0" - android:fill="#FF5722"/> + android:fillColor="#FF5722"/> <path android:pathData="M50.594,52.009l-3.0,0.0L47.594,51.0l-5.961,0.0l-0.003,3.289c0.0,0.826 0.668,1.494 1.494,1.494l11.948,0.0c0.826,0.0 1.494,-0.668 1.494,-1.494L56.566006,51.0l-5.972,0.0C50.594,51.0 50.594,52.009 50.594,52.009z" - android:fill="#FFFFFF"/> + android:fillColor="#FFFFFF"/> <path android:pathData="M47.594,49.009l3.0,0.0L50.594,50.0l6.22,0.0l0.0,-3.925c0.0,-0.826 -0.668,-1.494 -1.494,-1.494l-2.627,0.0l-7.131,-0.001l-2.713,0.0c-0.826,0.0 -1.486,0.668 -1.486,1.494L41.359,50.0l6.235,0.0L47.594,49.009z" - android:fill="#FFFFFF"/> + android:fillColor="#FFFFFF"/> <path android:pathData="M39.714,39.838 h18.221 v18.221 h-18.221z" - android:fill="#00000000"/> + android:fillColor="#00000000"/> <path android:pathData="M47.594,49.009 h3.0 v0.991 h-3.0z" - android:fill="#00000000"/> + android:fillColor="#00000000"/> <path android:pathData="M47.594,51.0 h3.0 v1.009 h-3.0z" - android:fill="#00000000"/> + android:fillColor="#00000000"/> <path android:pathData="M46.0,43.0l6.0,0.0l0.0,1.0l-6.0,0.0z" - android:fill="#FFFFFF"/> + android:fillColor="#FFFFFF"/> </vector> diff --git a/core/res/res/drawable/ic_lock_bugreport.xml b/core/res/res/drawable/ic_lock_bugreport.xml index b93a09a8e1ec..8540eee20a20 100644 --- a/core/res/res/drawable/ic_lock_bugreport.xml +++ b/core/res/res/drawable/ic_lock_bugreport.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" - android:height="32dp"/> - - <viewport + android:height="32dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="?attr/colorControlNormal" + android:fillColor="?attr/colorControlNormal" android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/> </vector> diff --git a/core/res/res/drawable/stat_notify_disabled_data.xml b/core/res/res/drawable/stat_notify_disabled_data.xml index d287a75b27f8..2f6ffaf12f50 100644 --- a/core/res/res/drawable/stat_notify_disabled_data.xml +++ b/core/res/res/drawable/stat_notify_disabled_data.xml @@ -13,25 +13,22 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" - android:height="24dp"/> - - <viewport + android:height="24dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M40.709,4.5l-6.604,7.337 0.0,16.601 6.604,6.604z"/> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M32.305,13.838l-6.0629997,6.7370005 6.0629997,6.0629997z"/> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M15.498,40.5l0.0,-7.9869995 -7.205,7.9869995z"/> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M10.265,9.72l-2.5460005,2.545 9.971001,9.971 3.7139988,3.7140007 -4.105999,4.5619984 0.0,9.988001 6.6019993,0.0 0.0,-12.054001 1.8029995,1.8030014 0.0,10.250999 6.602001,0.0 0.0,-3.6479988 1.7999992,1.7999992 1.8479996,1.8479996 4.670002,4.669998 2.5459976,-2.5459976z"/> </vector> diff --git a/core/res/res/drawable/vector_drawable_progress_bar_large.xml b/core/res/res/drawable/vector_drawable_progress_bar_large.xml index 6e0840c20ea8..3bf3cd70e328 100644 --- a/core/res/res/drawable/vector_drawable_progress_bar_large.xml +++ b/core/res/res/drawable/vector_drawable_progress_bar_large.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="76dp" - android:width="76dp" /> - - <viewport + android:width="76dp" android:viewportHeight="48" - android:viewportWidth="48" /> + android:viewportWidth="48" > <group android:name="root" @@ -29,9 +25,9 @@ android:translateY="24.0" > <path android:name="progressBar" - android:fill="#00000000" + android:fillColor="#00000000" android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38" - android:stroke="?attr/colorControlActivated" + android:strokeColor="?attr/colorControlActivated" android:strokeLineCap="round" android:strokeLineJoin="miter" android:strokeWidth="4" diff --git a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml index 7f1231c47cc4..62f9225b8548 100644 --- a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml +++ b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" - android:width="48dp" /> - - <viewport + android:width="48dp" android:viewportHeight="48" - android:viewportWidth="48" /> + android:viewportWidth="48" > <group android:name="root" @@ -29,9 +25,9 @@ android:translateY="24.0" > <path android:name="progressBar" - android:fill="#00000000" + android:fillColor="#00000000" android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38" - android:stroke="?attr/colorControlActivated" + android:strokeColor="?attr/colorControlActivated" android:strokeLineCap="round" android:strokeLineJoin="miter" android:strokeWidth="4" diff --git a/core/res/res/drawable/vector_drawable_progress_bar_small.xml b/core/res/res/drawable/vector_drawable_progress_bar_small.xml index 58ca10148097..1352cfcd3ef5 100644 --- a/core/res/res/drawable/vector_drawable_progress_bar_small.xml +++ b/core/res/res/drawable/vector_drawable_progress_bar_small.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="16dp" - android:width="16dp" /> - - <viewport + android:width="16dp" android:viewportHeight="48" - android:viewportWidth="48" /> + android:viewportWidth="48" > <group android:name="root" @@ -29,9 +25,9 @@ android:translateY="24.0" > <path android:name="progressBar" - android:fill="#00000000" + android:fillColor="#00000000" android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38" - android:stroke="?attr/colorControlActivated" + android:strokeColor="?attr/colorControlActivated" android:strokeLineCap="round" android:strokeLineJoin="miter" android:strokeWidth="4" diff --git a/core/res/res/layout/app_not_authorized.xml b/core/res/res/layout/app_not_authorized.xml index bd40eeb0b31d..2188511987f7 100644 --- a/core/res/res/layout/app_not_authorized.xml +++ b/core/res/res/layout/app_not_authorized.xml @@ -32,7 +32,7 @@ android:paddingBottom="16dip" android:paddingStart="16dip" android:paddingEnd="16dip" - android:text="@string/app_no_restricted_accounts" + android:text="@string/error_message_change_not_allowed" /> <!-- Horizontal divider line --> diff --git a/core/res/res/layout/app_permission_item.xml b/core/res/res/layout/app_permission_item.xml index e2ffffb77636..1eff3dce4568 100644 --- a/core/res/res/layout/app_permission_item.xml +++ b/core/res/res/layout/app_permission_item.xml @@ -27,8 +27,8 @@ <ImageView android:id="@+id/perm_icon" - android:layout_width="32dp" - android:layout_height="32dp" + android:layout_width="24dp" + android:layout_height="24dp" android:layout_marginStart="16dp" android:layout_marginEnd="8dp" android:scaleType="fitCenter" /> diff --git a/core/res/res/layout/app_permission_item_money.xml b/core/res/res/layout/app_permission_item_money.xml index 3fa465393837..7e1aca108ef3 100644 --- a/core/res/res/layout/app_permission_item_money.xml +++ b/core/res/res/layout/app_permission_item_money.xml @@ -27,8 +27,8 @@ <ImageView android:id="@+id/perm_icon" - android:layout_width="32dp" - android:layout_height="32dp" + android:layout_width="24dp" + android:layout_height="24dp" android:layout_marginStart="16dp" android:layout_marginEnd="8dp" android:scaleType="fitCenter" /> diff --git a/core/res/res/layout/app_permission_item_old.xml b/core/res/res/layout/app_permission_item_old.xml index ce0cd421262c..de6fc4fcbb0a 100644 --- a/core/res/res/layout/app_permission_item_old.xml +++ b/core/res/res/layout/app_permission_item_old.xml @@ -26,8 +26,8 @@ <ImageView android:id="@+id/perm_icon" - android:layout_width="30dip" - android:layout_height="30dip" + android:layout_width="24dip" + android:layout_height="24dip" android:layout_alignParentStart="true" android:scaleType="fitCenter" /> diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml index 1a7324ad7d2c..b5b5b277d84a 100644 --- a/core/res/res/layout/search_view.xml +++ b/core/res/res/layout/search_view.xml @@ -93,8 +93,7 @@ android:dropDownHeight="wrap_content" android:dropDownAnchor="@id/search_edit_frame" android:dropDownVerticalOffset="0dip" - android:dropDownHorizontalOffset="0dip" - android:contentDescription="@string/searchview_description_query" /> + android:dropDownHorizontalOffset="0dip" /> <ImageView android:id="@+id/search_close_btn" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index a0e4e98a5fcf..0545370f1d9a 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Laat die program toe om Bluetooth-MAP-boodskappe te ontvang en te verwerk. Dit beteken dat die program boodskappe wat na jou toestel gestuur word, kan monitor of uitvee sonder dat jy dit gesien het."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"haal lopende programme op"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Laat die program toe om inligting oor die huidig- en onlangslopende take op te haal. Dit kan moontlik die program toelaat om inligting oor watter programme op die toestel gebruik word, te ontdek."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interaksie tussen gebruikers"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Laat die program toe om aksies vir verskillende gebruikers op die toestel uit te voer. Kwaadwillige programme kan dit gebruik om die beskerming tussen gebruikers te skend."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"volle lisensie vir interaksie tussen gebruikers"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Laat die program toe om die blaaier se geskiedenis of boekmerke wat op jou foon gestoor is, te verander. Dit kan moontlik die program toelaat om blaaierdata uit te vee of te verander. Let wel: hierdie toestemming mag dalk nie deur derdeparty-blaaiers of ander programme met webblaaivermoëns afgedwing word nie."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"stel \'n wekker"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Laat die program toe om \'n alarm in \'n geïnstalleerde wekkerprogram te stel. Sommige wekkerprogramme werk dalk nie met hierdie funksie nie."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"skryf stemposse"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Laat die program toe om boodskappe uit jou stemposinkassie te wysig en te verwyder."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"voeg stemboodskap by"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Laat die program toe om boodskappe by te voeg by jou stempos-inkassie."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"lees stempos"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Laat die program toe om jou stemposse te lees."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"verander blaaier se geoligging-toestemmings"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Laat die program toe om die blaaier se geoligging-toestemmings te verander. Kwaadwillige programme kan dit gebruik om hulle toe te laat om ligginginligting aan enige webwerf te stuur."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"verifieer pakkies"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Stelsel"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Draadlose skerm"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Koppel aan toestel"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Saai skerm uit na toestel"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Soek tans vir toestelle…"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index fc9a8c854aca..ebbbdf0ae67d 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"መተግበሪያው የብሉቱዝ ኤምኤፒ መልእክቶችን እንዲቀበልና እንዲያካሂድ ይፈቅድለታል። ይህ ማለት መተግበሪያው ወደመሳሪያዎ የተላኩ መልእክቶችን ለእርስዎ ሳያሳይ ሊከታተል ወይም ሊሰረዝ ይችላል ማለት ነው።"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"አሂድ መተግበሪያዎችን ሰርስረው ያውጡ"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"መተግበሪያው በአሁኑ ጊዜና በቅርቡ እየተካሄዱ ስላሉ ተግባሮችን መረጃ ሰርስሮ እንዲያወጣ ይፈቅድለታል። ይህ መተግበሪያው በመሳሪያው ላይ የትኛዎቹ መተግበሪያዎች ጥቅም ላይ ስለመዋላቸው መረጃ እንዲያገኝ ሊፈቅድለት ይችላል።"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር መፍጠር"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"መተግበሪያው በመሣሪያው ላይ በተለያዩ ተጠቃሚዎች ላይ እርምጃዎችን እንዲፈጽም ይፈቅድለታል። ተንኮል-አዘል መተግበሪያዎች ይህንን ተጠቅመው በተጠቃሚዎች መካከል ያለውን ጥበቃ ሊጥሱ ይችላሉ።"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር ለመፍጠር ሙሉ ፍቃድ"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"መተግበሪያው ስልክህ ላይ የተከማቹ የአሳሹን ታሪክ ወይም ዕልባቶችን እንዲቀይር ይፈቅድለታል። ይህ መተግበሪያው የአሳሽ ውሂብ እንዲያጠፋ ወይም እንዲያስተካክል ሊፈቅድለት ይችላል። ማስታወሻ፦ ይህ ፈቃድ በሶስተኛ ወገን አሳሾች ወይም በሌላ የድር አሳሽነት አቅም ባላቸው መተግበሪያዎች ላይፈጸም ይችላል።"</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"ማንቂያ አስቀምጥ"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"በተጫነው የማንቂያ ሰዓት መተግበሪያ ውስጥ ማንቅያን ለማደራጀት ለመተግበሪያው ይፈቅዳሉ፡፡አንዳንድ የማንቂያ ሰዓት መተግበሪያዎች ይሄንን ባህሪ ላይፈፅሙ ይችላሉ፡፡"</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"የድምጽ መልእክቶችን ይጻፉ"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"መተግበሪያው ከድምጽ መልእክት የገቢ መልእክት ሳጥንዎ ውስጥ መልእክቶችን እንዲያስተካክልና እንዲያስወግድ ይፈቅዳል።"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"የድምፅ መልዕክት አክል"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ወደ ድምፅ መልዕክት የገቢ መልዕክትህ መልዕክቶች ለማከል ለመተግበሪያው ይፈቅዳሉ።"</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"የድምጽ መልእክት አንብብ"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"መተግበሪያዎ የድምጽ መልእክቶችን እንዲያነብ ይፈቅዳል።"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"የአሳሽ ገፀ ሥፍራ ፍቃዶችን ቀይር"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"የአሳሹን የጂኦ-አካባቢ ፍቃዶችን እንዲለውጥ ለመተግበሪያው ይፈቅዳል፡፡ተንኮል አዘል መተግበሪያዎች የመላኪያ አከባቢን መረጃ ወደ አጠራጣሪ የድር ጣቢያዎች ለመፍቀድ ይሄንን ሊጠቀሙበት ይችላሉ፡፡"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ፓኬጆችን አረጋግጥ"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"ስርዓት"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"የብሉቱዝ ድምጽ"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"ገመድ አልባ ማሳያ"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"የሚዲያ ውጽዓት"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"ከመሳሪያ ጋር ያገናኙ"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ማያ ገጽን ወደ መሣሪያ ይውሰዱ"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"መሳሪያዎችን በመፈለግ ላይ…"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 207754317c0c..eb17630772d9 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"يسمح للتطبيق بتلقي رسائل بلوتوث MAP ومعالجتها. وهذا يعني أنه سيكون بإمكان التطبيق الإشراف على أو حذف الرسائل المرسلة إليك بدون عرضها لك."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"استرداد التطبيقات التي قيد التشغيل"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"للسماح للتطبيق باسترداد معلومات حول المهام التي يجري تشغيلها حاليًا والتي تم تشغيلها مؤخرًا. وقد يسمح هذا للتطبيق باكتشاف معلومات حول التطبيقات المستخدمة على الجهاز."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"التعامل بين المستخدمين"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"للسماح للتطبيق بتنفيذ إجراءات بين مستخدمين مختلفين على الجهاز. قد تستخدم التطبيقات الضارة ذلك لانتهاك الحماية بين المستخدمين."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"الترخيص بالكامل للتعامل بين المستخدمين"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"النظام"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"عرض شاشة لاسلكي"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"المنفذ الإعلامي"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"الاتصال بجهاز"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"بث الشاشة على الجهاز"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"جارٍ البحث عن الأجهزة…"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index b87db9bd130e..8c7da0ff88da 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Разрешава на приложението да получава и обработва съобщения чрез Bluetooth MAP. Това означава, че то може да наблюдава или изтрива изпратените до устройството ви, без да ви ги покаже."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"извличане на изпълняваните приложения"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Разрешава на приложението да извлича информация за задачите, изпълнявани понастоящем и неотдавна. Това може да му позволи да открива данни за това, кои приложения се използват на устройството."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"взаимодействие с потребителите"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Разрешава на приложението да изпълнява действия за различни потребители на устройството. Злонамерените приложения може да използват това, за да нарушат защитата между потребителите."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"пълен лиценз за взаимодействие с потребителите"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Безжичен дисплей"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Свързване с устройство"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Екран за предаване към устройството"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Търсят се устройства…"</string> diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml index 81fee3a2cb02..8c1318d5b3b4 100644 --- a/core/res/res/values-bn-rBD/strings.xml +++ b/core/res/res/values-bn-rBD/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP বার্তা পেতে ও প্রক্রিয়া করতে অ্যাপ্লিকেশানটিকে অনুমতি দিন। এর অর্থ হলো, অ্যাপ্লিকেশানটি আপনাকে না দেখিয়েই আপনার ডিভাইসে পাঠানো বার্তা পর্যবেক্ষণ বা মুছতে পারবে।"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"চলমান অ্যাপ্লিকেশান উদ্ধার করে"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"বর্তমানে ও সাম্প্রতিককালের সক্রিয় ক্রিয়াগুলি সম্বন্ধে তথ্য পুনরুদ্ধার করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এছাড়া এটি ডিভাইসটিতে কোন অ্যাপ্লিকেশানগুলি ব্যবহৃত হচ্ছে তার বিষয়ে তথ্য খুঁজে বের করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করতে পারে৷"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"সামগ্রী ব্যবহারকারীদের সাথে ইন্টারঅ্যাক্ট করুন"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ডিভাইসটিতে থাকা বিভিন্ন ব্যবহারকারীর মধ্যে ক্রিয়াগুলির কার্য-সম্পাদনা করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি এটিকে ব্যবহারকারীদের মধ্যে সুরক্ষা লঙ্ঘন করতে ব্যবহার করতে পারে৷"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ব্যবহারকারীদের সাথে ইন্টারঅ্যাক্ট করার সম্পূর্ণ লাইসেন্স"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"অ্যাপ্লিকেশানটিকে আপনার ফোনে সঞ্চিত ব্রাউজারের ইতিহাস বা বুকমার্কগুলি পরিবর্তন করতে দেয়৷ এটি অ্যাপ্লিকেশানটিকে ব্রাউজার ডেটা মুছে দিতে বা পরিবর্তন করতে দেয়৷ দ্রষ্টব্য: এই অনুমতি তৃতীয় পক্ষের ব্রাউজারগুলির বা ওয়েব ব্রাউজিং ক্ষমতা সম্পন্ন অন্যান্য অ্যাপ্লিকেশানগুলি দ্বারা বলবৎ নাও হতে পারে৷"</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"একটি অ্যালার্ম সেট করুন"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"অ্যাপ্লিকেশানকে একটি ইনস্টল থাকা অ্যালার্ম অ্যাপ্লিকেশানে একটি অ্যালার্ম সেট করতে দেয়৷ কিছু অ্যালার্ম ঘড়ি অ্যাপ্লিকেশানগুলিতে ভবিষ্যতে এটি লাগু নাও হতে পারে৷"</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"ভয়েসমেলগুলি লিখুন"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"অ্যাপ্লিকেশানটিকে আপনার ভয়েসমেল ইনবক্স থেকে বার্তা পরিবর্তনের ও সরানোর অনুমতি দেয়৷"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"ভয়েসমেল যোগ করে"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"অ্যাপ্লিকেশানকে আপনার ভয়েসমেইল ইনবক্সে বার্তা যোগ করার অনুমতি দেয়৷"</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"ভয়েসমেল পড়ুন"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"অ্যাপ্লিকেশানটিকে আপনার ভয়েসমেলগুলি পড়ার অনুমতি দেয়।"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ব্রাউজারের ভূঅবস্থানিক অনুমতিগুলি সংশোধন করে"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"অ্যাপ্লিকেশানকে ব্রাউজারের ভূঅবস্থানিক অনুমতি সংশোধন করতে দেয়৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি নির্বিচারে ওয়েব সাইটগুলিতে অবস্থানের ডেটা পাঠানো সক্ষম করতে এটি ব্যবহার করতে পারে৷"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"প্যাকেজগুলি যাচাই করে"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"সিস্টেম"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth অডিও"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"ওয়্যারলেস প্রদর্শন"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"মিডিয়া আউটপুট"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"ডিভাইসে সংযোগ করুন"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ডিভাইসে স্ক্রীণ কাস্ট করুন"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"ডিভাইসগুলি অনুসন্ধান করা হচ্ছে…"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 7e693398a33e..b61a863f3e99 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permet que l\'aplicació rebi i processi missatges de Bluetooth MAP. Això vol dir que l\'aplicació pot controlar o suprimir missatges que s\'hagin enviat al teu dispositiu sense mostrar-te\'ls."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"recupera les aplicacions en execució"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permet que l\'aplicació recuperi informació sobre les tasques que s\'executen actualment i les que s\'han executat recentment. Aquesta acció pot permetre que l\'aplicació descobreixi informació sobre les aplicacions que s\'utilitzen al dispositiu."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interacciona entre usuaris"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permet que l\'aplicació dugui a terme accions en diferents usuaris del dispositiu. Les aplicacions malicioses poden fer servir aquest permís per infringir la protecció entre usuaris."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"llicència completa per interaccionar entre usuaris"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla sense fil"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortida de contingut multimèdia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexió al dispositiu"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emissió de pantalla al dispositiu"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"S\'estan cercant dispositius…"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 01c2cef37695..ffafe62ae6c1 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Umožňuje aplikaci přijímat a zpracovat zprávy Bluetooth MAP. To znamená, že aplikace může sledovat a mazat zprávy odeslané do zařízení, aniž by vám je zobrazila."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"načtení spuštěných aplikací"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Umožňuje aplikaci získat informace o aktuálně a naposledy spuštěných úlohách. Aplikace s tímto oprávněním může odhalit informace o aplikacích, které se v zařízení používají."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakce napříč uživateli"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umožňuje aplikaci provádět akce napříč různými uživateli zařízení. Škodlivé aplikace toto oprávnění mohou zneužít k obejití ochrany mezi uživateli."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"úplné oprávnění k interakcím napříč uživateli"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrátový displej"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Připojení k zařízení"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Odesílání obsahu obrazovky do zařízení"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Vyhledávání zařízení…"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 95bd92fbee22..5067669c31d5 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Tillader, at appen kan modtage og behandle Bluetooth MAP-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"hente kørende apps"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Tillader, at appen kan hente oplysninger om nuværende og seneste opgaver. Med denne tilladelse kan appen finde oplysninger om, hvilke applikationer der bruges på enheden."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kommunikere på tværs af brugere"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillader, at appen udfører handlinger på tværs af forskellige brugere på enheden. Ondsindede apps kan bruge dette til at krænke beskyttelsen mellem brugere."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"fuld licens til at kommunikere på tværs af brugere"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skærm"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieudgang"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Opret forbindelse til enheden"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Send skærm til enhed"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søger efter enheder…"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index b373ecd8b127..2bea17846c23 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Ermöglicht der App, Bluetooth MAP-Mitteilungen zu empfangen und zu verarbeiten. Das bedeutet, dass die App an Ihr Gerät gesendete Nachrichten überwachen und löschen kann, ohne sie Ihnen anzuzeigen."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"Aktive Apps abrufen"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Ermöglicht der App, Informationen zu aktuellen und kürzlich ausgeführten Aufgaben abzurufen. Damit kann die App möglicherweise ermitteln, welche Apps auf Ihrem Gerät zum Einsatz kommen."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Nutzerübergreifend interagieren"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ermöglicht der App, auf dem Gerät nutzerübergreifend Aktionen durchzuführen. Schädliche Apps können so den zwischen den Nutzern bestehenden Schutz aufheben."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Vollständige Lizenz zum nutzerübergreifenden Interagieren"</string> @@ -1386,8 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ermöglicht einer App die Anbindung an einen Trust Agent-Service"</string> <string name="permlab_recovery" msgid="3157024487744125846">"Mit Update- und Wiederherstellungssystem interagieren"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Ermöglicht einer App die Interaktion mit dem Wiederherstellungssystem und den Systemupdates"</string> - <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Sitzungen zum Projizieren von Medien"</string> - <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Ermöglicht einer App, Sitzungen zum Projizieren von Medien zu erstellen. In diesen Sitzungen können Apps Bildschirm- und Audioinhalte aufnehmen. Für normale Apps sollte dies nie erforderlich sein."</string> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Sitzungen zur Projektion von Medieninhalten erstellen"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Ermöglicht einer App, Sitzungen zur Projektion von Medieninhalten zu erstellen. In diesen Sitzungen können Apps Bildschirm- und Audioinhalte aufnehmen. Für normale Apps sollte dies nie erforderlich sein."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Für Zoomeinstellung zweimal berühren"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget konnte nicht hinzugefügt werden."</string> <string name="ime_action_go" msgid="8320845651737369027">"Los"</string> @@ -1512,10 +1516,10 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bearbeiten"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"Warnung zum Datenverbrauch"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"Für Verbrauch/Einstell. berühren"</string> - <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G/3G-Daten sind deaktiviert"</string> - <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G-Daten sind deaktiviert"</string> - <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Mobilfunkdaten sind deaktiviert"</string> - <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"WLAN-Daten sind deaktiviert"</string> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G/3G-Daten deaktiviert"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G-Daten deaktiviert"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Mobilfunkdaten deaktiviert"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"WLAN-Daten deaktiviert"</string> <string name="data_usage_limit_body" msgid="6131350187562939365">"Limit erreicht"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-/3G-Datenlimit überschritten"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G-Datenlimit überschritten"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-Audio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Kabellose Übertragung (WiDi)"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Medienausgabe"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Mit Gerät verbinden"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Bildschirm auf Gerät übertragen"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Geräte werden gesucht…"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index d3447b49fe83..3e7c2120daaf 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων MAP Bluetooth. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"ανάκτηση εκτελούμενων εφαρμογών"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Επιτρέπει στην εφαρμογή την ανάκτηση πληροφοριών σχετικά με τρέχουσες και πρόσφατα εκτελούμενες εργασίες. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να ανακαλύπτει πληροφορίες σχετικά με το ποιες εφαρμογές χρησιμοποιούνται στη συσκευή."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"αλληλεπίδραση στους χρήστες"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Δίνει στην εφαρμογή τη δυνατότητα να πραγματοποιεί ενέργειες σε όλους τους διαφορετικούς χρήστες στη συσκευή. Οι κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτή τη δυνατότητα για να παραβιάσουν την προστασία μεταξύ των χρηστών."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"πλήρης άδεια αλληλεπίδρασης στους χρήστες"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Σύστημα"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Ήχος Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Ασύρματη οθόνη"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Έξοδος μέσων"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Σύνδεση με τη συσκευή"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Μετάδοση οθόνης σε συσκευή"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Αναζήτηση συσκευών…"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index e7c501f828df..376c03bf8212 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Allows the app to receive and process Bluetooth MAP messages. This means that the app could monitor or delete messages sent to your device without showing them to you."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"retrieve running apps"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Allows the app to retrieve information about currently and recently running tasks. This may allow the app to discover information about which applications are used on the device."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interact across users"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Allows the app to perform actions across different users on the device. Malicious apps may use this to violate the protection between users."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"full license to interact across users"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Connect to device"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast screen to device"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Searching for devices…"</string> @@ -1728,7 +1733,7 @@ </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Try again later"</string> <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swipe down from the top to exit full screen."</string> - <string name="done_label" msgid="2093726099505892398">"Finished"</string> + <string name="done_label" msgid="2093726099505892398">"Done"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Hours circular slider"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string> <string name="select_hours" msgid="6043079511766008245">"Select hours"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index e7c501f828df..376c03bf8212 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Allows the app to receive and process Bluetooth MAP messages. This means that the app could monitor or delete messages sent to your device without showing them to you."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"retrieve running apps"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Allows the app to retrieve information about currently and recently running tasks. This may allow the app to discover information about which applications are used on the device."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interact across users"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Allows the app to perform actions across different users on the device. Malicious apps may use this to violate the protection between users."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"full license to interact across users"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Connect to device"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast screen to device"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Searching for devices…"</string> @@ -1728,7 +1733,7 @@ </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Try again later"</string> <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swipe down from the top to exit full screen."</string> - <string name="done_label" msgid="2093726099505892398">"Finished"</string> + <string name="done_label" msgid="2093726099505892398">"Done"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Hours circular slider"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string> <string name="select_hours" msgid="6043079511766008245">"Select hours"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index d5cc74323837..6a69085df5e3 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite que la aplicación reciba y procese mensajes por Bluetooth (MAP), lo que significa que podría controlar o eliminar mensajes enviados al dispositivo sin mostrártelos."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicaciones en ejecución"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite que la aplicación recupere información sobre las tareas que se estén ejecutando en ese momento o que se hayan ejecutado recientemente. La aplicación puede utilizar este permiso para descubrir cuáles son las aplicaciones que se utilizan en el dispositivo."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Interactuar con los usuarios"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que la aplicación lleve a cabo acciones entre los diferentes usuarios del dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para infringir la protección entre usuarios."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Licencia completa para interactuar con los usuarios"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite que la aplicación modifique el historial o los marcadores del navegador almacenados en el dispositivo. La aplicación puede utilizar este permiso para borrar o modificar los datos del navegador. Nota: Este permiso no puede ser utilizado por navegadores externos ni otras aplicaciones que tengan funciones de navegación por Internet."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"programar una alarma"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite que la aplicación establezca una alarma en una aplicación de alarma instalada. Es posible que algunas aplicaciones de alarma no incluyan esta función."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"Editar los mensajes del buzón de voz"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Permite que la aplicación modifique y elimine mensajes de la bandeja de entrada del buzón de voz."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"agregar correo de voz"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite que la aplicación agregue mensajes a la bandeja de entrada de tu buzón de voz."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"Consultar los mensajes del buzón de voz"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Permite que la aplicación consulte los mensajes del buzón de voz."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Modificar los permisos de ubicación geográfica del navegador"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite que la aplicación modifique los permisos de ubicación geográfica del navegador. Las aplicaciones maliciosas pueden utilizar esto para permitir el envío de información de ubicación a sitios web arbitrarios."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"Verificar paquetes"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar al dispositivo"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir pantalla a dispositivo"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 0405f7ccfc3f..bf77e1d09867 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite que la aplicación reciba y procese mensajes por Bluetooth (MAP), lo que significa que podría utilizar este permiso para controlar o eliminar mensajes enviados al dispositivo sin mostrárselos al usuario."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicaciones en ejecución"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite que aplicación recupere información sobre tareas que se están ejecutando en ese momento o que se han ejecutado recientemente. La aplicación puede utilizar este permiso para descubrir cuáles son las aplicaciones que se utilizan en el dispositivo."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interactuar con los usuarios"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que la aplicación lleve a cabo acciones entre los diferentes usuarios del dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para infringir la protección entre usuarios."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licencia completa para interactuar con los usuarios"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar a dispositivo"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Enviar pantalla a dispositivo"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index 9c740c2fc492..4f044f390126 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Võimaldab rakendusel vastu võtta ja töödelda Bluetoothi MAP-sõnumeid. See tähendab, et rakendus saab teie seadmesse saadetud sõnumeid jälgida või kustutada ilma neid teile näitamata."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"Käitatud rakenduste toomine"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Võimaldab rakendusel tuua teavet praegu ja hiljuti käitatud ülesannete kohta. See võib lubada rakendusel avastada teavet selle kohta, milliseid rakendusi seadmes kasutatakse."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"toimingud erinevatel kasutajakontodel"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Lubab rakendusel teha toiminguid seadme erinevatel kasutajakontodel. Pahatahtlikud rakendused võivad kasutada seda kasutajatevahelise kaitse rikkumiseks."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"täielik litsents teha toiminguid erinevatel kasutajakontodel"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Süsteem"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Juhtmeta ekraan"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Meediaväljund"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Seadmega ühendamine"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekraanikuva ülekandmine seadmesse"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Seadmete otsimine …"</string> diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml index 2bf1850af1aa..75ef54392d7d 100644 --- a/core/res/res/values-eu-rES/strings.xml +++ b/core/res/res/values-eu-rES/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP mezuak jaso eta prozesatzeko baimena ematen die aplikazioei. Horrela, aplikazioek gailura bidalitako mezuak kontrola eta ezaba ditzakete, mezuak zuri erakutsi gabe."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"Eskuratu abian diren aplikazioak"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Unean edo duela gutxi exekutatutako zereginei buruzko informazioa lortzeko baimena ematen die aplikazioei. Horrela, aplikazioak gailuan erabiltzen ari diren aplikazioei buruzko informazioa ezagut dezake."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"erabiltzaileekin elkarrekintzan jardutea"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Gailuaren erabiltzaileetan ekintzak gauzatzeko baimena ematen die aplikazioei. Aplikazio gaiztoek erabil dezakete erabiltzaileen arteko babesa urratzeko."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"erabiltzaileekin elkarrekintzan jarduteko baimen osoa"</string> @@ -443,9 +447,9 @@ <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Beste aplikazioen cache-direktorioetako fitxategiak ezabatuta telefono-memorian tokia egiteko baimena ematen die aplikazioei. Hori eginez gero, beste aplikazio horiek motelago abiarazi daitezke, datuak berriro lortu beharko dituztelako."</string> <string name="permlab_movePackage" msgid="3289890271645921411">"Aldatu tokiz aplikazioen baliabideak"</string> <string name="permdesc_movePackage" msgid="319562217778244524">"Aplikazio-baliabideak barneko euskarritik kanpoko batera (eta alderantziz) eramatea baimentzen die aplikazioei."</string> - <string name="permlab_readLogs" msgid="6615778543198967614">"Irakurri egunkarietako isilpeko datuak"</string> - <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Sistemaren askotariko egunkari-fitxategiak irakurtzea baimentzen die aplikazioei. Horrela, tabletarekin egiten ari zarenari buruzko informazio orokorra aurki dezakete, eta isilpekoa edo pertsonala den informazioa ere barne har daiteke."</string> - <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Sistemaren askotariko egunkari-fitxategiak irakurtzea baimentzen die aplikazioei. Horrela, telefonoarekin egiten ari zarenari buruzko informazio orokorra aurki dezakete, eta isilpekoa edo pertsonala den informazioa ere barne har daiteke."</string> + <string name="permlab_readLogs" msgid="6615778543198967614">"Irakurri erregistroetako isilpeko datuak"</string> + <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Sistemaren askotariko erregistro-fitxategiak irakurtzea baimentzen die aplikazioei. Horrela, tabletarekin egiten ari zarenari buruzko informazio orokorra aurki dezakete, eta isilpekoa edo pertsonala den informazioa ere barne har daiteke."</string> + <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Sistemaren askotariko erregistro-fitxategiak irakurtzea baimentzen die aplikazioei. Horrela, telefonoarekin egiten ari zarenari buruzko informazio orokorra aurki dezakete, eta isilpekoa edo pertsonala den informazioa ere barne har daiteke."</string> <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"erreprodukziorako edozein multimedia-deskodetzaile erabiltzea"</string> <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Instalatutako edozein multimedia-deskodetzaile erabiltzeko baimena ematen die aplikazioei, gauzak erreproduzitu ahal izateko deskodetzeko."</string> <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Kudeatu kredentzial fidagarriak"</string> @@ -1181,11 +1185,11 @@ <string name="whichApplication" msgid="4533185947064773386">"Gauzatu ekintza hau erabilita:"</string> <string name="whichApplicationNamed" msgid="8260158865936942783">"Osatu ekintza %1$s erabiliz"</string> <string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin:"</string> - <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin honekin: %1$s"</string> + <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin %1$s aplikazioarekin"</string> <string name="whichEditApplication" msgid="144727838241402655">"Editatu honekin:"</string> - <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu honekin: %1$s"</string> + <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu %1$s aplikazioarekin"</string> <string name="whichSendApplication" msgid="6902512414057341668">"Partekatu honekin:"</string> - <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partekatu honekin: %1$s"</string> + <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partekatu %1$s aplikazioarekin"</string> <string name="whichHomeApplication" msgid="4616420172727326782">"Hautatu hasierako pantailako aplikazio bat"</string> <string name="alwaysUse" msgid="4583018368000610438">"Erabili modu lehenetsian ekintza honetarako."</string> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Garbitu aplikazio lehenetsia Sistemaren ezarpenak > Aplikazioak > Deskargatutakoak atalean."</string> @@ -1386,7 +1390,7 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Konfiantza zehazteko agente baten zerbitzuari lotzea baimentzen die aplikazioei."</string> <string name="permlab_recovery" msgid="3157024487744125846">"Interaktuatu eguneratze- eta eskuratze-sistemekin"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Eskuratze-sistemarekin nahiz sistema-eguneratzeekin interaktuatzeko aukera ematen die aplikazioei."</string> - <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Sortu multimedia-elementuak proiektatzeko saioak"</string> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Sortu multimedia-edukia proiektatzeko saioak"</string> <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Multimedia-elementuak proiektatzeko saioak sortzea baimentzen die aplikazioei. Saio horiekin, aplikazioek pantailan bistaratutakoa eta audioa graba ditzakete. Aplikazio normalek ez lukete behar."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Ukitu birritan zooma kontrolatzeko"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Ezin izan da widgeta gehitu."</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetootharen audioa"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Hari gabeko pantaila"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Multimedia-irteera"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Konektatu gailura"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Igorri pantaila gailura"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Gailuak bilatzen…"</string> @@ -1747,7 +1752,7 @@ <string name="lock_to_app_negative" msgid="2259143719362732728">"EZ, ESKERRIK ASKO"</string> <string name="lock_to_app_positive" msgid="7085139175671313864">"HASI"</string> <string name="lock_to_app_start" msgid="3074665051586318340">"Aplikazio batean blokeatuta"</string> - <string name="lock_to_app_exit" msgid="8967089657201849300">"Pantaila ez dago jada aplikazio bakarrean blokeatuta"</string> + <string name="lock_to_app_exit" msgid="8967089657201849300">"Aplikazio bakarreko modutik irten egin da"</string> <string name="lock_to_app_use_screen_lock" msgid="1434584309048590886">"Irten aurretik, eskatu %1$s"</string> <string name="lock_to_app_unlock_pin" msgid="7908385370846820001">"PIN kodea"</string> <string name="lock_to_app_unlock_pattern" msgid="7763071104790758405">"desblokeatzeko eredua"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 596daa891ea5..468dde46c8f5 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"به برنامه اجازه میدهد پیامهای بلوتوث MAP را دریافت و پردازش کند. این یعنی برنامه میتواند پیامهای ارسالی به دستگاه شما را بدون نمایش آنها به شما حذف یا کنترل کند."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"بازیابی برنامههای در حال اجرا"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"به برنامه امکان میدهد اطلاعات مربوط به کارهای در حال اجرای اخیر و کنونی را بازیابی کند. این ممکن است به برنامه امکان دهد به اطلاعات مربوط به برنامههایی که در دستگاه استفاده میشوند دست یابد."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ارتباط بین کاربران"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"به برنامه اجازه میدهد اقداماتی در بین کاربران مختلف در دستگاه انجام دهد. ممکن است برنامههای مخرب از این قابلیت برای نقض حفاظت موجود در بین کاربران استفاده کنند."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"مجوز کامل برای ارتباط بین کاربران"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"سیستم"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوثهای صوتی"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"صفحه نمایش بیسیم"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"برقراری ارتباط با دستگاه"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"فرستادن صفحه نمایش به دستگاه"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"در حال جستجو برای دستگاهها..."</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 07a4c6ed716f..ed04c3ae3f8e 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Antaa sovelluksen vastaanottaa ja käsitellä Bluetooth MAP -viestejä. Sovellus voi valvoa ja poistaa laitteeseesi lähetettyjä viestejä näyttämättä niitä sinulle."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"käynnissä olevien sovellusten noutaminen"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Antaa sovelluksen noutaa tietoja käynnissä olevista ja äskettäin suoritetuista tehtävistä. Sovellus voi saada tietoja laitteella käytetyistä sovelluksista."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"suorita käyttäjien välisiä toimintoja"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Antaa sovelluksen suorittaa käyttäjien välisiä toimintoja laitteessa. Haitalliset sovellukset voivat vahingoittaa käyttäjien välistä suojausta."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lupa suorittaa käyttäjien välisiä toimintoja"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Antaa sovelluksen muokata selaimen historiaa ja puhelimeen tallennettuja kirjanmerkkejä. Sovellus voi poistaa tai muokata selaimen tietoja. Huomaa: kolmannen osapuolen selaimet tai muut sovellukset, jotka pystyvät selaamaan verkkoa, eivät saa käyttää tätä lupaa."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"aseta herätys"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Antaa sovelluksen asettaa hälytyksen sisäiseen herätyskellosovellukseen. Jotkin herätyskellosovellukset eivät välttämättä käytä tätä ominaisuutta."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"vastaajaviestien kirjoitus"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Antaa sovelluksen muokata ja poistaa puhelinvastaajaan saapuneita viestejä."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"lisää vastaajaviesti"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Antaa sovelluksen lisätä viestejä saapuneisiin vastaajaviesteihin."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"vastaajaviestien luku"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Antaa sovelluksen lukea vastaajaviestisi."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"selaimen maantieteellisen sijainnin lupien muokkaaminen"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Antaa sovelluksen muokata Selaimen maantieteellisen sijainnin lupia. Haitalliset sovellukset voivat sallia tällä sijaintitietojen lähettämisen mielivaltaisiin sivustoihin."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"vahvista paketteja"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Järjestelmä"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ääni"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Langaton näyttö"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Median äänentoisto"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Yhdistä laitteeseen"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Lähetä näyttö laitteeseen"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Etsitään laitteita…"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 19db01abc152..39a1a9f76d82 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permet à l\'application de recevoir et traiter des messages par Bluetooth à l\'aide du profil MAP. Cela signifie que l\'application peut contrôler ou supprimer les messages envoyés à votre appareil sans vous les montrer."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"récupérer les données des applications en cours d\'exécution"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permet à l\'application de récupérer des données sur des tâches en cours d\'exécution et récemment exécutées. L\'application est ainsi susceptible d\'obtenir des données concernant les applications utilisées sur l\'appareil."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagir entre les utilisateurs"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permet à l\'application d\'effectuer des actions entre les différents utilisateurs de l\'appareil. Les applications malveillantes peuvent utiliser cette autorisation pour passer outre la protection entre les utilisateurs."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"autorisation totale d\'interagir entre les utilisateurs"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permet à l\'application de modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Cette autorisation peut lui permettre d\'effacer ou de modifier les données du navigateur. Remarque : il est possible que cette autorisation ne soit pas appliquée par les navigateurs tiers ni par d\'autres applications permettant de naviguer sur le Web."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"définir une alarme"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Permet à l\'application de régler la sonnerie d\'une fonction de réveil installée sur votre appareil. Cette fonctionnalité n\'est pas compatible avec toutes les applications de réveils."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"modifier les messages vocaux"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Autoriser l\'application à modifier et à supprimer des messages de la boîte de réception des messages vocaux."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"ajouter des messages vocaux"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permet à l\'application d\'ajouter des messages à votre messagerie vocale."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"accéder aux messages vocaux"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Autoriser l\'application à accéder à vos messages vocaux."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modifier les autorisations de géolocalisation du navigateur"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permet à l\'application de modifier les autorisations de géolocalisation du navigateur. Des applications malveillantes peuvent exploiter cette fonctionnalité pour permettre l\'envoi de données de localisation à des sites Web arbitraires."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"vérifier les paquets"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Diffuser l\'écran sur l\'appareil"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index eea8ad9d31be..e28d70f39fea 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permet à l\'application de recevoir et traiter des messages MAP Bluetooth. Cela signifie que l\'application peut contrôler ou supprimer les messages envoyés à votre appareil sans vous les montrer."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"récupérer les applications en cours d\'exécution"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permet à l\'application de récupérer des informations sur des tâches en cours d\'exécution et récemment exécutées. L\'application est ainsi susceptible d\'obtenir des informations sur les applications utilisées sur l\'appareil."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagir entre les utilisateurs"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permet à l\'application d\'effectuer des actions entre les différents utilisateurs de l\'appareil. Les applications malveillantes peuvent utiliser cette autorisation pour passer outre la protection entre les utilisateurs."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"autorisation totale d\'interagir entre les utilisateurs"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permet à l\'application de modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Cette autorisation peut lui permettre d\'effacer ou de modifier les données du navigateur. Remarque : il est possible que cette autorisation ne soit pas appliquée par les navigateurs tiers ni par d\'autres applications permettant de naviguer sur le Web."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"définir une alarme"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Permet à l\'application de régler la sonnerie d\'un réveil installé. Cette fonctionnalité n\'est pas disponible sur tous les réveils."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"modifier les messages vocaux"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Autoriser l\'application à modifier et à supprimer des messages de la boîte de réception des messages vocaux"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"ajouter un message vocal"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permet à l\'application d\'ajouter des messages à votre messagerie vocale."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"accéder à la messagerie vocale"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Autoriser l\'application à accéder à votre messagerie vocale"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modifier les autorisations de géolocalisation du navigateur"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permet à l\'application de modifier les autorisations de géolocalisation du navigateur. Des applications malveillantes peuvent exploiter cette fonctionnalité pour permettre l\'envoi de données de localisation à des sites Web arbitraires."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"vérifier les packages"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Caster l\'écran sur l\'appareil"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index eb7a45b09ae3..6f9e9e75958f 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite que a aplicación reciba e procese as mensaxes de MAP por Bluetooth. Isto quere dicir que a aplicación podería controlar ou eliminar as mensaxes enviadas ao teu dispositivo sen mostrarchas."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicacións en execución"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite á aplicación recuperar información acerca de tarefas que se están executando actualmente ou que se executaron recentemente. É posible que esta acción permita á aplicación descubrir información acerca de que aplicacións se utilizan no dispositivo."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interactuar entre os usuarios"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite á aplicación levar a cabo accións nos diferentes usuarios do dispositivo. É posible que aplicacións maliciosas utilicen isto para vulnerar a protección entre os usuarios."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licenza completa para interactuar entre os usuarios"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio por Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Visualización sen fíos"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída multimedia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar co dispositivo"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emisión de pantalla no dispositivo"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index b2665e333fd1..6bf9c709688e 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ऐप्स को Bluetooth MAP संदेशों को प्राप्त करने और भेजने देती है. इसका अर्थ है कि ऐप्स आपके उपकरण पर भेजे गए संदेशों को आपको दिखाए बिना ही मॉनीटर कर सकता है या उन्हें हटा सकता है."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे ऐप्स पुनर्प्राप्त करें"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"ऐप्स को वर्तमान में और हाल ही में चल रहे कार्यों के बारे में जानकारी को पुन: प्राप्त करने देता है. इससे ऐप्स उपकरण पर उपयोग किए गए ऐप्स के बारे में जानकारी खोज सकता है."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"उपयोगकर्ताओं के बीच सहभागिता करें"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ऐप्स को उपकरण पर भिन्न उपयोगकर्ताओं के बीच कार्य निष्पादित करने देता है. दुर्भावनापूर्ण ऐप्स उपयोगकर्ताओं के बीच सुरक्षा का उल्लंघन करने के लिए इसका उपयोग कर सकते हैं."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"उपयोगकर्ताओं के बीच सहभागिता करने के लिए पूर्ण लाइसेंस"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्टम"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस प्रदर्शन"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"मीडिया आउटपुट"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"उपकरण से कनेक्ट करें"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"स्क्रीन को उपकरण में कास्ट करें"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"उपकरण खोजे जा रहे हैं…"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 28832331f68c..a01d72d24fda 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Aplikaciji omogućuje primanje i obradu Bluetooth MAP poruka. To znači da aplikacija može nadzirati ili brisati poruke poslane na vaš uređaj, a da vam ih ne prikaže."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"dohvaćanje pokrenutih aplikacija"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Aplikaciji omogućuje dohvaćanje informacija o trenutačnim i nedavnim tekućim zadacima. To aplikaciji može omogućiti otkrivanje informacija o tome koje se aplikacije upotrebljavaju na uređaju."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakcija među korisnicima"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Omogućuje aplikaciji izvršavanje radnji među korisnicima na uređaju. Zlonamjerne aplikacije mogu to iskoristiti za narušavanje zaštite među korisnicima."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"dozvola za potpunu interakciju među korisnicima"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sustav"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični prikaz"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijski izlaz"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Povezivanje s uređajem"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emitiranje zaslona na uređaj"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Traženje uređaja…"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 4dfa0db40cd6..68a5dff45b28 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Lehetővé teszi az alkalmazás számára, hogy Bluetooth MAP üzeneteket fogadjon és dolgozzon fel. Ez azt jelenti, hogy az alkalmazás anélkül figyelheti meg vagy törölheti a beérkező üzeneteket, hogy megjelenítené azokat Önnek."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"futó alkalmazások lekérése"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Lehetővé teszi az alkalmazás számára a jelenleg futó és nemrég befejezett feladatokkal kapcsolatos információk lekérését. Ezáltal az alkalmazás engedélyt kap az eszközön használt alkalmazásokkal kapcsolatos információk felderítésére."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"felhasználók közötti interakció"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Lehetővé teszi az alkalmazás számára, hogy több felhasználó között végezzen különféle műveleteket az eszközön. A rosszindulatú alkalmazások arra használhatják ezt, hogy megsértsék a felhasználók biztonságát."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"teljes licenc a felhasználók közötti interakcióhoz"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Rendszer"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Vezeték nélküli kijelző"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Médiakimenet"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Csatlakozás adott eszközhöz"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Képernyő átküldése az eszközre"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Eszközkeresés…"</string> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index 942a2791207e..7bf62074bc13 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Թույլ է տալիս հավելվածին ստանալ և մշակել Bluetooth MAP հաղորդագրությունները: Սա նշանակում է, որ հավելվածը կարող է ստուգել կամ ջնջել ձեր սարքին ուղարկված հաղորդագրությունները` առանց դրանք ձեզ ցուցադրելու:"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"առբերել աշխատող հավելվածները"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Թույլ է տալիս հավելվածին առբերել մանրամասն տեղեկություններ առկա և վերջերս աշխատող առաջադրանքների մասին: Սա կարող է թույլ տալ հավելվածին հայտնաբերել անձնական տեղեկություններ այլ հավելվածների վերաբերյալ:"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"հաղորդակցվել օգտվողների միջև"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Թույլ է տալիս հավելվածին իրականացնել գործողություններ սարքի տարբեր օգտվողների միջոցով: Վնասարար հավելվածները կարող են օգտագործել սա` խախտելու օգտվողների միջև պաշտպանությունը:"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ամբողջական հաղորդակցվելու արտոնություն օգտվողների միջև"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Թույլ է տալիս հավելվածին փոփոխել դիտարկչի պատմությունը կամ ձեր հեռախոսում պահված էջանիշերը: Այն կարող է թույլ տալ հավելվածին ջնջել կամ փոփոխել դիտարկչի տվյալները: Նշում. այս թույլտվությունը չի կարող գործածվել կողմնակի դիտարկիչների կամ վեբ զննարկման հնարավորություններով այլ հավելվածների կողմից:"</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"դնել ազդանշան"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Թույլ է տալիս հավելվածին սահմանել զարթուցիչի ծրագրում տեղադրված ազդանշանը: Զարթուցիչի որոշ հավելվածներ չեն կարող կիրառել այս հատկությունը:"</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"գրել ձայնային փոստ"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Ծրագրին թույլ է տալիս մուտքի արկղից փոփոխել և հեռացնել ձեր ձայնային փոստը:"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"ավելացնել ձայնային փոստ"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Թույլ է տալիս հավելվածին ավելացնել հաղորդագրություններ ձեր ձայնային փոստի արկղում:"</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"կարդալ ձայնային փոստը"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Ծրագրին թույլ է տալիս կարդալ ձեր ձայնային փոստը"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"փոփոխել դիտարկչի աշխարհագրական տեղանքի թույլտվությունները"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Թույլ է տալիս հավելվածին փոփոխել զննարկչի աշխարհագրական դիրքի թույլտվությունները: Վնասարար հավելվածները կարող են օգտագործել սա` թույլատրելու ուղարկել տեղադրության վերաբերյալ տեղեկությունները կամայական վեբ կայքերին:"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"հաստատել փաթեթները"</string> @@ -1390,10 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ծրագրին թույլ է տալիս կապվել վստահելի գործակալի ծառայությանը:"</string> <string name="permlab_recovery" msgid="3157024487744125846">"Փոխազդել թարմացման և վերականգնման համակարգի հետ"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Թույլ է տալիս ծրագրին փոխազդել վերականգնման համակարգի և համակարգի թարմացումների հետ:"</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Ստեղծել մեդիայի տեսարձակման աշխատաշրջաններ"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Ծրագրին թույլ է տալիս ստեղծել մեդիայի տեսարձակման աշխատաշրջաններ: Այդ աշխատաշրջանները կարող են ծրագրերին թույլ տալ հավաքագրել էկրանի և աուդիոյի բովանդակությունը: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Հպեք երկու անգամ` դիտափոխման կարգավորման համար"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Չհաջողվեց վիջեթ ավելացնել:"</string> <string name="ime_action_go" msgid="8320845651737369027">"Առաջ"</string> @@ -1518,20 +1516,14 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Խմբագրել"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"Տվյալների օգտագործման նախազգուշացում"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"Հպեք` օգտագործումը և կարգավորումները տեսնելու համար:"</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G տվյալների կապն անջատված է"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G տվյալների կապն անջատված է"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Բջջային տվյալներն անջատված են"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi տվյալներն անջատված են"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"Սահմանաչափը սպառվեց"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G տվյալների սահմանը գերազանցված է"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G տվյալների սահմանը գերազանցվել է"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Բջջային տվյալների չափը սպառվեց"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi տվյալների սահմանը գերազանցվել է"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g>-ը գերազանցում է նշված սահմանաչափը:"</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"Հետնաշերտային տվյալները սահմանափակ են"</string> @@ -1567,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Համակարգ"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի ձայնանյութ"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Անլար էկրան"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Մեդիա արտածում"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Միանալ սարքին"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Հեռարձակել էկրանը սարքի վրա"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Որոնվում են սարքեր..."</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 327d2ac552bb..a730c8d1a5b8 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Mengizinkan aplikasi menerima dan memproses pesan MAP Bluetooth. Artinya, aplikasi dapat memantau atau menghapus pesan yang dikirim ke perangkat Anda tanpa menunjukkannya kepada Anda."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"mengambil apl yang berjalan"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Memungkinkan aplikasi mengambil informasi tentang tugas yang dijalankan saat ini dan baru-baru ini. Izin ini memungkinkan aplikasi menemukan informasi tentang aplikasi mana yang digunakan pada perangkat."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"berinteraksi antar-pengguna"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Mengizinkan aplikasi melakukan tindakan antar-pengguna yang berbeda pada perangkat. Aplikasi berbahaya dapat menggunakan ini untuk mengganggu perlindungan antar-pengguna."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lisensi penuh untuk berinteraksi antar-pengguna"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Layar nirkabel"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Keluaran media"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Sambungkan ke perangkat"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmisi layar ke perangkat"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Menelusuri perangkat…"</string> diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml index c76d4d79100a..564b4e8afd57 100644 --- a/core/res/res/values-is-rIS/strings.xml +++ b/core/res/res/values-is-rIS/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Leyfir forritinu að taka á móti og vinna úr Bluetooth MAP-skilaboðum. Þetta þýðir að forritið getur fylgst með eða eytt skilaboðum sem send eru í tækið án þess að sýna þér þau."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"sækja forrit í gangi"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Leyfir forriti að sækja upplýsingar um opin forrit og forrit sem nýlega hafa verið opin. Þetta getur gert forritinu kleift að nálgast upplýsingar um forritin sem notuð eru í tækinu."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"samskipti á milli notenda"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Leyfir forriti að framkvæma aðgerðir á milli notenda tækisins. Spilliforrit geta notað þetta til að brjóta á bak aftur vörn á milli notenda."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"fullt leyfi til að eiga í samskiptum notenda á milli"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Kerfi"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-hljóð"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Þráðlaus skjábirting"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Margmiðlunarúttak"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Tengjast tæki"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Senda skjá út í tæki"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Leitar að tækjum…"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index bf821f5f137b..8d7a210cb255 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Consente all\'app di ricevere ed elaborare i messaggi Bluetooth MAP. Questo significa che l\'app può monitorare o eliminare i messaggi inviati al tuo dispositivo senza mostrarteli."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"recupero applicazioni in esecuzione"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Consente all\'applicazione di recuperare informazioni sulle attività attualmente e recentemente in esecuzione. Ciò potrebbe consentire all\'applicazione di scoprire informazioni sulle applicazioni in uso sul dispositivo."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interazione tra gli utenti"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Consente all\'applicazione di compiere azioni per diversi utenti sul dispositivo. Le applicazioni dannose potrebbero farne uso per violare la protezione tra utenti."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licenza completa per l\'interazione tra utenti"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Visualizzazione wireless"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Uscita media"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Connetti al dispositivo"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Trasmetti schermo al dispositivo"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Ricerca di dispositivi in corso…"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index cba87701607b..82d9242345b1 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"הרשאה זו מאפשרת לאפליקציה לקבל ולעבד הודעות MAP של Bluetooth. משמעות הדבר היא שהאפליקציה יכולה לעקוב אחר הודעות הנשלחות למכשיר שלך או למחוק אותן מבלי להראות לך אותן."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"אחזור אפליקציות פעילות"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"מאפשר לאפליקציה לאחזר מידע לגבי משימות הפועלות כרגע ושפעלו לאחרונה. ייתכן שהדבר יתיר לאפליקציה לגלות מידע לגבי האפליקציות שבהן נעשה שימוש במכשיר."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"אינטראקציה בין משתמשים"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"מאפשר לאפליקציה לבצע פעולות בין משתמשים שונים במכשיר. אפליקציות זדוניות עשויות להשתמש ביכולת זו כדי לפרוץ את ההגנה בין משתמשים."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"רישיון מלא לבצע אינטראקציה בין משתמשים"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"מאפשר לאפליקציה לשנות את ההיסטוריה או ה-Bookmarks של הדפדפן המאוחסנים בטלפון. הדבר עשוי לאפשר לאפליקציה למחוק או לשנות נתוני דפדפן. שים לב: אישור זה אינו ניתן לאכיפה על ידי דפדפני צד שלישי או אפליקציות אחרות בעלות יכולות גלישה באינטרנט."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"הגדרת התראה"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"מאפשר לאפליקציה להגדיר התראה באפליקציה מותקנת של שעון מעורר. אפליקציות מסוימות של שעון מעורר אינן מיישמות תכונה זו."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"כתיבת הודעות דואר קולי"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"מאפשרת לאפליקציה לשנות ולהסיר הודעות מתיבת הדואר הנכנס של דואר קולי."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"הוסף דואר קולי"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"מאפשר לאפליקציה להוסיף הודעות לתיבת הדואר הקולי."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"קריאת דואר קולי"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"מאפשרת לאפליקציה לקרוא את הודעות הדואר הקולי שלך."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"שינוי הרשאות המיקום הגיאוגרפי של הדפדפן"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"מאפשר לאפליקציה לשנות את הרשאות המיקום הגיאוגרפי של הדפדפן. אפליקציות זדוניות עלולות להשתמש בכך כדי לאפשר משלוח של פרטי מיקום לאתרים זדוניים אחרים."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"אימות חבילות"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"מערכת"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"אודיו Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"צג אלחוטי"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"פלט מדיה"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"התחברות למכשיר"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"העברת מסך אל מכשיר"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"מחפש מכשירים…"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 00be975f0f5f..aa7774d1d16d 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAPメッセージの受信と処理をアプリに許可します。これにより、端末に届いたメッセージをアプリが表示することなく監視または削除するおそれがあります。"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"実行中のアプリの取得"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"現在実行中または最近実行したタスクに関する情報の取得をアプリに許可します。これにより、その端末でどのアプリを使用しているかをアプリから識別できるようになる可能性があります。"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ユーザー間の交流"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"端末上の各ユーザーに対して操作を実行することをアプリに許可します。この許可を悪意のあるアプリに利用されると、ユーザー間の保護が侵害される恐れがあります。"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ユーザー間で交流するための完全ライセンス"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"システム"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"ワイヤレスディスプレイ"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"端末に接続"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"端末への画面のキャスト"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"端末を検索しています…"</string> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index 86d6e66f5a21..cb3f60ffe208 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"აპს შეეძლება Bluetooth MAP შეტყობინებების მიღება და დამუშავება. ეს ნიშნავს, რომ აპს შეეძლება შეტყობინებების მონიტორინგი და მათი წაშლა თქვენთვის ჩვენების გარეშე."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"მოქმედი აპების მოძიება"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"აპს შეეძლება მოიძიოს ინფორმაცია ამჟამად და უახლოეს წარსულში მიმდინარე ამოცანების შესახებ. ამგვარად, აპს აქვს შესაძლებლობა აღმოაჩინოს ინფორმაცია იმის შესახებ, თუ რომელი აპლიკაციებია გამოყენებული მოწყობილობაზე."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"მომხმარებლებს შორის ინტერაქცია"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"აპს შეეძლება, სხვადასხვა მომხმარებლის მოქმედებები შეასრულოს მოწყობილობაზე. მავნე აპებმა შეიძლება მომხმარებლებს შორის დაცვის დასარღვევად გამოიყენონ."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"მომხმარებლებთან ინტერაქციის სრული ლიცენზია"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"აპს შეეძლება, შეცვალოს ბრაუზერის ისტორია და თქვენ ტელეფონში შენახული სანიშნეები. ამან შეიძლება უფლება მისცეს აპს, წაშალოს ან შეცვალოს ბრაუზერის მონაცემები. შენიშვნა: ეს ნებართვა არ შეიძლება შესრულდეს მესამე მხარის ბრაუზერების ან ვებ დათვალიერების შესაძლებლობის მქონე სხვა აპლიკაციების მიერ."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"მაღვიძარას დაყენება"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"აპს შეეძლება მაღვიძარას დაყენება დაინსტალირებული მაღვიძარას აპლიკაციაში. ამ ფუნქციას მაღვიძარას ზოგიერთი აპი არ იყენებს."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"ხმოვანი ფოსტის ჩათვლით"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"ნებას რთავს ამ აპს, შეცვალოს და ამოშალოს შეტყობინებები თქვენი ხმოვანი ფოსტის შემოსულებიდან."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"ხმოვანი ფოსტის დამატება"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"აპს შეეძლება დაამატოს შეტყობინებები თქვენი ხმოვანი ფოსტის შემოსულებში."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"ხმოვანი ფოსტის წაკითხვა"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"აპს ეძლევა მთელი თქვენი ხმოვანი ფოსტების წაკითხვის უფლება."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ბრაუზერის გეოლოკაციის უფლებების შეცვლა"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"აპს შეეძლება ბრაუზერის გეოლოკაციის უფლებების შეცვლა. მავნე აპებმა ეს შესაძლოა გამოიყენონ ნებისმიერი ვებსაიტისთვის მდებარეობის შესახებ ინფორმაციის გასაგზავნად."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"პაკეტების გადამოწმება"</string> @@ -1295,7 +1295,7 @@ <string name="sim_removed_message" msgid="5450336489923274918">"ფიჭური კავშირი არ იქნება ხელმისაწვდომი, ვიდრე არ ჩადებთ ქმედით SIM ბარათს და გადატვირთავთ."</string> <string name="sim_done_button" msgid="827949989369963775">"დასრულდა"</string> <string name="sim_added_title" msgid="3719670512889674693">"SIM ბარათი დაემატა"</string> - <string name="sim_added_message" msgid="7797975656153714319">"გადატვირთთ თქვენი მოწყობილობა ფიჭურ ქსელზე წვდომისთვის."</string> + <string name="sim_added_message" msgid="7797975656153714319">"გადატვირთეთ თქვენი მოწყობილობა ფიჭურ ქსელზე წვდომისთვის."</string> <string name="sim_restart_button" msgid="4722407842815232347">"გადატვირთვა"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"დროის დაყენება"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"თარიღის დაყენება"</string> @@ -1390,10 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"საშუალებას აძლევს აპლიკაციას მიემაგროს სანდო აგენტის სერვისს."</string> <string name="permlab_recovery" msgid="3157024487744125846">"განახლებასთან და აღდგენის სისტემასთან ინტერაქცია"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"საშუალებას აძლევს აპლიკაციას მოახდინოს აღდგენის სისტემასთან და სისტემის განახლებასთან ინტერაქცია."</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"მედია პროეცირების სესიების შექმნა"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"საშუალებას აძლევს აპლიკაციას, შექმნას მედია პროეცირების სესიები. ამ სესიებმა შესაძლოა მისცეს აპლიკაციებს საშუალება, აღიბეჭდოს ეკრანისა და აუდიოს კონტენტი. ჩვეულებრივ აპს წესით ეს არასოდეს არ უნდა დასჭირდეს."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"მასშტაბის მართვისთვის შეეხეთ ორჯერ."</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ვერ დაემატა ვიჯეტი."</string> <string name="ime_action_go" msgid="8320845651737369027">"გადასვლა"</string> @@ -1518,20 +1516,14 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"რედაქტირება"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"ინტერნეტის გამოყენების გაფრთხილება"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"შეეხეთ მოხმარებისა და პარამეტრების სანახავად."</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G მონაც. გადაცემა გამორთულია"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G მონაც. გადაცემა გამორთულია"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"ფიჭური ინტერნეტი გამორთულია"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi მონაც. გადაცემა გამორთულია"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"ლიმიტი მიღწეულია"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"გადაჭარბებულია 2G-3G მონაცემების ლიმიტი"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G ლიმიტი გადაჭარბებულია"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"ფიჭ. ინტერნეტის ლიმიტი მიღწეულია"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi‑Fi მონაცემთა ლიმიტი გადაჭარბებულია"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"ლიმიტი გადაჭარბებულია <xliff:g id="SIZE">%s</xliff:g>-ით."</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"მონაცემთა ფონური გადაცემა შეზღუდულია"</string> @@ -1567,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"სისტემა"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth აუდიო"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"უსადენო ეკრანი"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"მედია გამომავალი"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"მოწყობილობასთან დაკავშირება"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ეკრანის მოწყობილობაზე გადაცემა"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"მოწყობილობების ძიება…"</string> diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml index dd24dcfa5249..172e45a33b91 100644 --- a/core/res/res/values-kk-rKZ/strings.xml +++ b/core/res/res/values-kk-rKZ/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Қолданбаға Bluetooth MAP хабарларын алуға және өңдеуге рұқсат береді. Бұл қолданба құрылғыңызға жіберілген хабарларды сізге көрсетпестен бақылауы немесе жоюы мүмкін екенін білдіреді."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"жұмыс істеп жатқан қолданбаларды шығарып алу"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Қолданбаларға ағымдағы және соңғы тапсырмалар туралы ақпарат алу мүмкіндігін береді. Бұл қолданбаға құрылғы қолданатын басқа қолданбалар туралы деректері анықтау мүмкіндігін беруі ықтимал."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"барлық пайдаланушылармен қарым-қатынас жасау"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Қолданбаға құрылғыдағы әртүрлі пайдаланушылар арасында әрекеттер орындау мүмкіндігін береді. Залалды қолданбалар бұны пайдаланушылар арасындағы қорғанысты бұзу үшін пайдалануы мүмкін."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"барлық пайдаланушылармен қарым-қатынас жасау лицензиясы"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Қолданбаларға телефонда сақталған Браузер кіріп шыққан барлық URL тарихын және Браузер бетбелгілерін өзгерту мүмкіндігін береді. Есіңізде болсын: бұл рұқсатты үшінші жақ браузерлері немесе веб шолу қабілеті бар басқа қолданбалар қолданбауы мүмкін."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"дабылды орнату"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Қолданбаға орнатылған оятқыш қолданбасында дабылды орнатуға рұқсат береді. Кейбір қолданбаларда бұл мүмкіндік іске асырылмауы мүмкін."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"дауыстық хабарлар жазу"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Қолданбаға дауыстық поштаңыздың «Кіріс» қалтасындағы хабарларды өзгертуге және жоюға рұқсат етеді."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"дауыс хабарын қосу"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Қолданбаға дауыстық поштаңыздың «Кіріс» қалтасына хабарлар қосуға рұқсат береді."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"дауыстық поштаны оқу"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Қолданбаға дауыстық хабарларыңызды оқуға рұқсат етеді."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"браузердің геолокация рұқсаттарын өзгерту"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Қолданбаға браузердің геолокация рұқсаттарын өзгертуге рұқсат береді. Зиянкес қолданбалар мұны кездейсоқ веб-сайттарға орын туралы ақпаратты жіберуге рұқсат беру үшін пайдалануы мүмкін."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"жинақтарды растау"</string> @@ -1390,10 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Қолданбаға сенімді агент қызметіне байластыруға рұқсат береді."</string> <string name="permlab_recovery" msgid="3157024487744125846">"Жаңарту және қалпына келтіру жүйелерімен қатынасу"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Қолданбаның қалпына келтіру жүйесімен және жүйе жаңартуларымен қатынасу мүмкіндігін береді."</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Тасушыны проекциялау сеанстарын жасау"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Қолданбаға тасушыны проекциялау сеанстарын жасауға рұқсат етеді. Бұл сеанстар қолданбаларға дисплей және аудио мазмұнын түсіру мүмкіндігін қамтамасыз етеді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Масштабтауды басқару үшін екі рет түртіңіз"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетті қосу."</string> <string name="ime_action_go" msgid="8320845651737369027">"Өту"</string> @@ -1518,20 +1516,14 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгерту"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"Дерекқор қолдануға қатысты ескерту"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"Қолданыс және параметрлерді көру үшін түртіңіз."</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G деректері өшірулі"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G деректері өшірулі"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Ұялы деректер өшірулі"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi деректері өшірулі"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"Шекке жеттіңіз"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2Г-3Г дерекқор шектеуінен асып кетті"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4Ш дерекқор шектеуінен асып кетті"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Ұялы деректер шегі асырылды"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi дерекқор шектеуінен асып кетті"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Анықталған уақтыттан <xliff:g id="SIZE">%s</xliff:g> асты."</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"Тарихы туралы дерекқор шектелген"</string> @@ -1567,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Жүйе"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth aудио"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Сымсыз дисплей"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Meдиа шығысы"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Құрылғыға жалғау"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Экранды құрылғымен байланыстыру"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Құрылғыларды іздеуде…"</string> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index ba6c0ac9e24e..7b2c26c058e8 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ឲ្យកម្មវិធីទទួល និងដំណើរការសារ MAP ប៊្លូធូស។ មានន័យថា កម្មវិធីអាចតាមដាន ឬលុបសារដែលបានផ្ញើទៅឧបករណ៍របស់អ្នកដោយមិនបង្ហាញពួកវាដល់អ្នក។"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"ទៅយកកម្មវិធីកំពុងដំណើរការ"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"ឲ្យកម្មវិធីទៅយកព័ត៌មានលម្អិតអំពីកិច្ចការដែលកំពុងដំណើរការបច្ចុប្បន្ន។ វាអាចឲ្យកម្មវិធីរកមើលព័ត៌មានថាតើកម្មវិធីណាមួយត្រូវបានប្រើលើឧបករណ៍។"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"អន្តរកម្មតាមអ្នកប្រើ"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ឲ្យកម្មវិធីអនុវត្តសកម្មភាពឆ្លងអ្នកប្រើផ្សេងៗលើឧបករណ៍។ កម្មវិធីព្យាបាទអាចប្រើវា ដើម្បីបំពានការការពាររវាងអ្នកប្រើ។"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"អាជ្ញាប័ណ្ណពេញលេញ ដើម្បីទាក់ទងអ្នកប្រើ"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ឲ្យកម្មវិធីកែប្រវត្តិ ឬចំណាំរបស់កម្មវិធីអ៊ីនធឺណិតដែលបានរក្សាទុកក្នុងទូរស័ព្ទរបស់អ្នក។ កម្មវិធីព្យាបាទអាចប្រើវាដើម្បីលុប ឬកែទិន្នន័យនៃកម្មវិធីអ៊ីនធឺណិតរបស់អ្នក។ ចំណាំ៖ សិទ្ធិនេះអាចត្រូវបានបង្ខំដោយកម្មវិធីអ៊ីនធឺណិតភាគីទីបី ឬកម្មវិធីផ្សេងដែលមានសមត្ថភាពរុករកបណ្ដាញ។ស"</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"កំណត់សំឡេងរោទ៍"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"ឲ្យកម្មវិធីកំណត់សំឡេងរោទ៍ក្នុងកម្មវិធីនាឡិការោទ៍បានដំឡើង។ កម្មវិធីនាឡិការោទ៍មួយចំនួនអាចមិនអនុវត្តលក្ខណៈនេះ។"</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"សរសេរសារជាសំឡេង"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"ឲ្យកម្មវិធីកែប្រែ និងលុបសារចេញពីប្រអប់ទទួលសារជាសំឡេងរបស់អ្នក។"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"បន្ថែមសារជាសំឡេង"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ឲ្យកម្មវិធីបន្ថែមសារទៅប្រអប់ទទួលសារជាសំឡេងរបស់អ្នក។"</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"អានសារជាសំឡេង"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"ឲ្យកម្មវិធីអានសារជាសំឡេងរបស់អ្នក។"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"កែសិទ្ធិទីតាំងភូមិសាស្ត្ររបស់កម្មវិធីអ៊ីនធឺណិត"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ឲ្យកម្មវិធីកែសិទ្ធិទីតាំងភូមិសាស្ត្ររបស់កម្មវិធីអ៊ីនធឺណិត។ កម្មវិធីព្យាបាទអាចប្រើវា ដើម្បីឲ្យផ្ញើព័ត៌មានទីតាំងទៅតំបន់បណ្ដាញដោយបំពាន។"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ផ្ទៀងផ្ទាត់កញ្ចប់"</string> @@ -1561,7 +1561,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"ប្រព័ន្ធ"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"សំឡេងប៊្លូធូស"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"បង្ហាញបណ្ដាញឥតខ្សែ"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"លទ្ធផលមេឌៀ"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"ភ្ជាប់ឧបករណ៍"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ចាត់ថ្នាក់អេក្រង់ទៅឧបករណ៍"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"កំពុងស្វែងរកឧបករណ៍..."</string> diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml index d6143e16bbd8..cedab617a7d9 100644 --- a/core/res/res/values-kn-rIN/strings.xml +++ b/core/res/res/values-kn-rIN/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ಬ್ಲೂಟೂಟ್ MAP ಸಂದೇಶಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ಮತ್ತು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಇದರರ್ಥ, ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಕಳುಹಿಸಲಾಗಿರುವ ಸಂದೇಶಗಳನ್ನು ನಿಮಗೆ ತೋರಿಸದೆಯೇ, ಅಪ್ಲಿಕೇಶನ್ ಅವುಗಳನ್ನು ಮಾನಿಟರ್ ಮಾಡಬಹುದು ಅಥವಾ ಅಳಿಸಬಹುದು."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"ರನ್ ಆಗುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಹಿಂಪಡೆಯಿರಿ"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"ಪ್ರಸ್ತುತವಿರುವ ಮತ್ತು ಇತ್ತೀಚಿಗೆ ಚಾಲ್ತಿಯಾಗಿರುವ ಕಾರ್ಯಗಳ ಕುರಿತ ಮಾಹಿತಿಯನ್ನು ಮರುಪಡೆದುಕೊಳ್ಳಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಇದು ಸಾಧನದಲ್ಲಿ ಯಾವ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬಳಸಲಾಗಿದೆ ಎಂಬುದರ ಕುರಿತ ಮಾಹಿತಿಯನ್ನು ಅನ್ವೇಷಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸಬಹುದು."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ಬಳಕೆದಾರರ ಜೊತೆ ಸಂವಹನ ನಡೆಸಿ"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ಸಾಧನದಲ್ಲಿರುವ ವಿವಿಧ ಬಳಕೆದಾರರಾದ್ಯಂತ ಕ್ರಿಯೆಗಳನ್ನು ನಿರ್ವಹಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಇದನ್ನು ಬಳಕೆದಾರರ ನಡುವಿನ ರಕ್ಷಣೆಯನ್ನು ಉಲ್ಲಂಘಿಸಲು ಬಳಸಿಕೊಳ್ಳಬಹುದು."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ಬಳಕೆದಾರರ ಜೊತೆಗೆ ಸಂವಹನ ನಡೆಸಲು ಪೂರ್ಣ ಪರವಾನಗಿ"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"ಸಿಸ್ಟಂ"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೊ"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"ವಯರ್ಲೆಸ್ ಪ್ರದರ್ಶನ"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"ಮೀಡಿಯಾ ಔಟ್ಪುಟ್"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಿ"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ಸಾಧನಕ್ಕೆ ಬಿತ್ತರಿಸುವ ಪರದೆ"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 7b9c05a87c75..81547002f4d7 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"앱이 블루투스 MAP 메시지를 수신하고 처리하도록 허용합니다. 이는 앱이 나에게 보여주지 않고 내 기기에 전송된 메시지를 모니터링하거나 삭제할 수 있음을 의미합니다."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"실행 중인 앱 검색"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"앱이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 허용합니다. 이 경우 앱이 기기에서 사용되는 다른 앱에 대한 정보를 검색할 수 있습니다."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"여러 사용자와의 상호작용"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"앱이 기기에서 다양한 사용자에 대한 작업을 수행할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자 간의 보호를 위반할 수 있습니다."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"여러 사용자와의 상호작용을 위한 정식 라이선스"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"앱이 휴대전화에 저장된 브라우저 기록 또는 북마크를 수정할 수 있도록 허용합니다. 이 경우 앱이 브라우저 데이터를 삭제 또는 수정할 수 있습니다. 참고: 이 권한은 타사 브라우저 또는 브라우저 기능을 가진 기타 애플리케이션에 적용되지 않습니다."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"알람 설정"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"앱이 설치된 알람 시계 앱에서 알람을 설정할 수 있도록 허용합니다. 일부 알람 시계 앱에는 이 기능이 구현되지 않을 수 있습니다."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"음성사서함 쓰기"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"앱이 음성사서함에서 메시지를 수정하고 삭제하도록 허용합니다."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"음성사서함 추가"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"앱이 음성사서함에 메시지를 추가할 수 있도록 허용합니다."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"음성사서함 읽기"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"앱이 음성사서함을 읽도록 허용합니다."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"브라우저 위치 정보 권한 수정"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"앱이 브라우저의 위치 정보 권한을 수정할 수 있도록 허용합니다. 이 경우 악성 앱이 이 기능을 이용하여 임의의 웹사이트에 위치 정보를 보낼 수 있습니다."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"패키지 확인"</string> @@ -1391,7 +1391,7 @@ <string name="permlab_recovery" msgid="3157024487744125846">"업데이트 및 복구 시스템과 상호작용"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"애플리케이션이 복구 시스템 및 시스템 업데이트와 상호작용할 수 있도록 허용합니다."</string> <string name="permlab_createMediaProjection" msgid="4941338725487978112">"미디어 프로젝션 세션 만들기"</string> - <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"애플리케이션이 미디어 프로젝션 세션을 만드는 것을 허용합니다. 이 세션은 애플리케이션에 디스플레이 및 오디오 컨텐츠를 캡처하는 기능을 제공할 수 있습니다. 일반 앱에는 필요하지 않습니다."</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"애플리케이션이 미디어 프로젝션 세션을 만드는 것을 허용합니다. 이 세션은 애플리케이션에 디스플레이 및 오디오 콘텐츠를 캡처하는 기능을 제공할 수 있습니다. 일반 앱에는 필요하지 않습니다."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"확대/축소하려면 두 번 터치하세요."</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"위젯을 추가할 수 없습니다."</string> <string name="ime_action_go" msgid="8320845651737369027">"이동"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"시스템"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"무선 디스플레이"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"기기에 연결"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"기기로 화면 전송"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"기기 검색 중…"</string> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index 2ab9816be052..7a1c96b0fd3a 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -430,6 +430,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Колдонмого Bluetooth MAP билдирүүлөрүн алуу жана иштеп чыгуу мүмкүнчүлүгүн берет. Демек, колдонмо түзмөгүңүздөгү билдирүүлөрдү сизге көрсөтпөстөн тескеп же жок кыла алат."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"иштеп жаткан колдонмолорду түшүрүп алуу"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Колдонмого учурдагы жана акыркы убакытта пайдаланылган колдонмолор тууралуу маалымат алууга уруксат берет. Бул колдонмого түзмөктө кандай колдонмолор колдонулаарын билип алууга жол бериши мүмкүн."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"колдонуучулар менен иштешүү"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Колдонмого түзмөктөгү ар кандай колдонуучулардын атынан кыймыл-аракеттерди жүргүзүү уруксатын берет. Зыяндуу колдонмолор, муну менен колдонуучулар аарсындагы коргонду бузуп салышы мүмкүн."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"колдонуучулар менен иштешүү үчүн толук лицензия"</string> @@ -1340,16 +1344,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Колдонмого телефонуңузда сакталган Серепчинин тарыхын жана Серепчинин бүктөмөлөрүн өзгөртүү уруксатын берет. Бул колдонмого Серепчинин берилиштерин өчүрүү же өзгөртүү уруксатын берет. Эскертүү: бул уруксат үчүнчү тараптык интернет-серепчилерге, же интернетке кирүү мүмкүнчүлүгү бар колдонмолорго таасир этпеши мүмкүн."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"ойготкуч коюу"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Колдонмого ойготкуч саат колдонмосуна үн ишаратын коюу мүмкүнчүлүгүн берет. Айрым ойготкуч саат колдонмолорунда бул мүмкүнчүлүк иштебеши мүмкүн."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"үн почталарын жазуу"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Колдонмонун үн почтаңыздын кирүү кутусунан билдирүүлөрдү өзгөртүп жана алып салуусуна жол ачат."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"үнкат кошуу"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Колдонмого үн почтаңыздын кирүү кутусуна билдирүүлөрдү кошуу мүмкүнчүлүгүн берет."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"үн почтасын окуу"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Колдонмонун үн почталарыңызды окуусуна жол ачат."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Серепчинин гео-жайгашуу уруксаттарын өзгөртүү"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Колдонмого Серепчинин гео-жайгашуу уруксаттарын өзгөртүү мүмкүнчүлүгүн берет. Кесепеттүү колдонмолор ушундай мүмкүнчүлүктөн пайдаланып ар кайсы вебсайтка жайгашкан жер жөнүндө маалыматтын жөнөтүлүшүнө уруксат берип салышы мүмкүн."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"таңгактарды текшерүү"</string> @@ -1809,10 +1809,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Колдонмого ишенимдүү агент кызматына жалгашууга мүмкүнчүлүк берет."</string> <string name="permlab_recovery" msgid="3157024487744125846">"Калыбына келтирүү системасы жана жаңыртуулар менен иштөө"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Колдонмого калыбына келтирүү системасы жана система жаңыртуулары менен карым-катнашуу мүмкүнчүлүгүн берет."</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Медиа чагылдыруу сеанстарын түзүү"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Колдонмого медиа чагылдыруу сеанстарын түзүү мүмкүнчүлүгүн берет. Мындай сеанстардын жардамы менен, колдонмолор дисплей жана видео мазмунду сүрөткө тартып турушат. Кадимки колдонмолор үчүн талап кылынбайт."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Чен өлчөмүн көзөмөлдөө үчүн эки жолу тийип коюңуз"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетти кошуу мүмкүн болбоду."</string> <!-- no translation found for ime_action_go (8320845651737369027) --> @@ -1986,20 +1984,14 @@ <!-- no translation found for data_usage_warning_title (1955638862122232342) --> <skip /> <string name="data_usage_warning_body" msgid="2814673551471969954">"Колдонууну көрүш үчүн басыңыз."</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2Гб-3Гб көлмдөгү дайындр өчүрлдү."</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4Гб көлөмдөгү дайындар өчүрүлдү"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Уюктук дайындар тармагы өчүк"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi дайындар тармагы өчүк"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"Белгиленген чекке жеттиңиз"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G трафик чектен ашты"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G трафик чектен ашты"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Уюкт дайндр белглнгн чегнн аштңз"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi трафик чегинен ашты"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Орнотулган чектөөдөн <xliff:g id="SIZE">%s</xliff:g> ашты."</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"Фондук трафик чектелген"</string> @@ -2049,7 +2041,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Зымсыз дисплей"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Медиа чыгаруу"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Түзмөккө туташуу"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Сырткы экранга чыгаруу"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Түзмөктөр изделүүдө..."</string> diff --git a/core/res/res/values-large/themes_material.xml b/core/res/res/values-large/themes_material.xml index 27816080c284..05fee6b35693 100644 --- a/core/res/res/values-large/themes_material.xml +++ b/core/res/res/values-large/themes_material.xml @@ -35,6 +35,10 @@ please see themes_device_defaults.xml. <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Dialog.NoActionBar.FixedSize"> <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item> </style> - <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light.Dialog.FixedSize" /> - <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.Dialog.NoActionBar.FixedSize" /> + <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light.Dialog.FixedSize"> + <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item> + </style> + <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.Dialog.NoActionBar.FixedSize"> + <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item> + </style> </resources> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index 22404ff55fd1..7b9c218e8b24 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ອະນຸຍາດໃຫ້ແອັບຯສາມາດຮັບແລະສົ່ງຂໍ້ຄວາມ Bluetooth MAP ໄດ້. ນີ້ໝາຍຄວາມວ່າແອັບຯຈະສາມາດກວດເບິ່ງ ຫຼືລຶບຂໍ້ຄວາມທີ່ສົ່ງຫາອຸປະກອນຂອງທ່ານໄດ້ໂດຍບໍ່ສະແດງຂໍ້ຄວາມເຫຼົ່ານັ້ນໃຫ້ທ່ານເຫັນ."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"ດຶງແອັບຯທີ່ເຮັດວຽກຢູ່ມາ"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນກ່ຽວກັບການເຮັດວຽກໃນປັດຈຸບັນ ແລະຫາກໍຜ່ານມາ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດຄົ້ນພົບຂໍ້ມູນ ກ່ຽວກັບແອັບພລິເຄຊັນທີ່ໃຊ້ຢູ່ໃນອຸປະກອນໄດ້."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ການຕອບໂຕ້ລະຫວ່າງຜູ່ໃຊ້"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ອະນຸຍາດໃຫ້ແອັບຯດຳເນີນການ ສັ່ງງານຜ່ານຜູ່ໃຊ້ອື່ນໆໃນອຸປະກອນ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດໃຊ້ຄວາມສາມາດນີ້ ເພື່ອລະເມີດການປ້ອງກັນລະຫວ່າງຜູ່ໃຊ້."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ໃບອະນຸຍາດສະບັບເຕັມໃນການໂຕ້ຕອບລະຫວ່າງຜູ່ໃຊ້"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"ລະບົບ"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ສຽງ Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"ການສະແດງຜົນໄຮ້ສາຍ"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"ມີເດຍເອົ້າພຸດ"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"ເຊື່ອມຕໍ່ຫາອຸປະກອນ"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ສົ່ງພາບໜ້າຈໍໄປຫາອຸປະກອນ"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"ກຳລັງຊອກຫາອຸປະກອນ..."</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 5eb55c156b81..61dcf8695084 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Programai leidžiama gauti ir apdoroti „Bluetooth“ MAP pranešimus. Tai reiškia, kad programa gali stebėti ir ištrinti į jūsų įrenginį siunčiamus pranešimus jums jų neparodžiusi."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"nuskaityti vykdomas programas"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Leidžiama programai nuskaityti informaciją apie šiuo ir pastaruoju metu vykdomas užduotis. Taip programa gali atrasti informacijos, kokios programos naudojamos įrenginyje."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"sąveikauti su naudotojais"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Leidžiama programai atlikti veiksmus skirtingų įrenginio naudotojų profiliuose. Kenkėjiškos programos gali pasinaudoti šiuo leidimu, kad pažeistų naudotojų saugumą."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"visa licencija, leidžianti sąveikauti su naudotojais"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Belaidis rodymas"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijos išvestis"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Prijungimas prie įrenginio"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Perduoti ekraną į įrenginį"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Ieškoma įrenginių…"</string> @@ -1743,7 +1748,7 @@ <string name="lock_to_app_toast" msgid="2126866321272822564">"Įjungėte programos užrakinimo funkcijos režimą. Kad išeitumėte, palieskite ir palaikykite mygtuką „Naujausios“"</string> <string name="lock_to_app_toast_locked" msgid="4229650395479263497">"Įjungėte programos užrakinimo funkcijos režimą."</string> <string name="lock_to_app_title" msgid="5895142291937470019">"Naudoti programos užrakinimo funkciją?"</string> - <string name="lock_to_app_description" msgid="2800403592608529611">"Naudojant programos užrakinimo funkciją ekrane užrakinama viena programa.\n\nKad išeitumėte, palieskite ir palaikykite mygtuką „Naujausios“"</string> + <string name="lock_to_app_description" msgid="2800403592608529611">"Naudojant programos užrakinimo funkciją ekrane užrakinama viena programa.\n\nKad išeitumėte, palieskite ir palaikykite mygtuką „Naujausios“."</string> <string name="lock_to_app_negative" msgid="2259143719362732728">"NE, AČIŪ"</string> <string name="lock_to_app_positive" msgid="7085139175671313864">"ĮJUNGTI"</string> <string name="lock_to_app_start" msgid="3074665051586318340">"Naudojama programos užrakinimo funkcija"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index f005960b9c00..e4cd1fe75c4f 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Ļauj lietotnei saņemt un apstrādāt Bluetooth MAP ziņojumus. Tas nozīmē, ka lietotne var pārraudzīt vai dzēst uz jūsu ierīci nosūtītos ziņojumus, neparādot tos jums."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"izgūt izmantotās lietotnes"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Ļauj lietotnei izgūt informāciju par pašreiz un nesen darbinātajiem uzdevumiem. Tādējādi lietotne var atklāt informāciju par ierīcē izmantotajām lietojumprogrammām."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"darboties visos lietotāju kontos"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ļauj lietotnei veikt darbības vairāku ierīces lietotāju kontos. Ļaunprātīgas lietotnes var izmantot šo atļauju, lai apdraudētu lietotāju kontu drošību."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"pilna licence ar atļauju darboties visos lietotāju kontos"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistēma"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezvadu attēlošana"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Multivides izeja"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Savienojuma izveide ar ierīci"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekrāna apraide uz ierīci"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Notiek ierīču meklēšana…"</string> diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index d49a8248aa90..0e54fe56a3ef 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Овозможува апликацијата да прима и да обработува пораки МАП преку Bluetooth. Тоа значи дека апликацијата може да следи или да брише пораки испратени до вашиот уред без да ви ги прикаже вам."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"обнови активни апликации"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Овозможува апликацијата да поврати информации за тековно и до неодамна активни задачи. Ова може да овозможи апликацијата да открие информации за тоа кои апликации се користат на уредот."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"комуницирај со корисници"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Овозможува апликацијата да врши дејства кај различни корисници на уредот. Злонамерните апликации може да го искористат тоа да ја нарушат заштитата меѓу корисниците."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"целосна дозвола за комуникација меѓу корисници"</string> @@ -1557,7 +1561,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудио на Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Безжичен приказ"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Излез за медиуми"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Поврзи се со уред"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Префрли екран на уред"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Пребарување за уреди..."</string> diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml index 9115ba2e1e96..f994247707f9 100644 --- a/core/res/res/values-ml-rIN/strings.xml +++ b/core/res/res/values-ml-rIN/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP സന്ദേശങ്ങൾ സ്വീകരിക്കുന്നതിനും പ്രോസസ്സുചെയ്യുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉപകരണത്തിലേക്ക് അയച്ച സന്ദേശങ്ങൾ നിങ്ങളെ കാണിക്കാതെ തന്നെ നിരീക്ഷിക്കാനോ ഇല്ലാതാക്കാനോ അപ്ലിക്കേഷനാവും."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"പ്രവർത്തിക്കുന്ന അപ്ലിക്കേഷനുകൾ വീണ്ടെടുക്കുക"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"നിലവിലും സമീപകാലത്തും പ്രവർത്തിക്കുന്ന ടാസ്ക്കുകളെക്കുറിച്ചുള്ള വവിവരങ്ങൾ വീണ്ടെടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് ഉപകരണത്തിൽ ഉപയോഗിച്ച അപ്ലിക്കേഷനുകളെക്കുറിച്ചുള്ള വിവരം കണ്ടെത്താൻ അപ്ലിക്കേഷനെ അനുവദിക്കാനിടയുണ്ട്."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"എല്ലാ ഉപയോക്താക്കളുമായും സംവദിക്കുക"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ഉപകരണത്തിലെ വ്യത്യസ്ത ഉപയോക്താക്കളിലുടനീളം പ്രവർത്തനങ്ങൾ നടത്താൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ ഉപയോക്താക്കൾക്കിടയിലുള്ള പരിരക്ഷ ലംഘിക്കാൻ ഇത് ഉപയോഗിക്കാനിടയുണ്ട്."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"എല്ലാ ഉപയോക്താക്കളുമായും സംവദിക്കാനുള്ള പൂർണ്ണ ലൈസൻസ്"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"സിസ്റ്റം"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ഓഡിയോ"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"വയർലെസ് ഡിസ്പ്ലേ"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"മീഡിയ ഔട്ട്പുട്ട്"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"ഉപകരണത്തിലേക്ക് കണക്റ്റുചെയ്യുക"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"സ്ക്രീൻ ഉപകരണത്തിലേക്ക് കാസ്റ്റുചെയ്യുക"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"ഉപകരണങ്ങൾക്കായി തിരയുന്നു…"</string> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index ea33e8cfc5b6..e5334a500056 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -298,6 +298,8 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Апп нь Блютүүт MAP мессежийг хүлээн авах болон гүйцэтгэх боломжтой. Ингэснээр апп нь таны төхөөрөмжрүү илгээсэн мессежийг танд үзүүлэхгүйгээр хянах болон устгаж чадна."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"ажиллаж байгаа апп-г дуудах"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Апп нь одоо ажиллаж байгаа болон сүүлд ажилласан даалгаврын талаарх мэдээллийг авах боломжтой. Ингэснээр апп нь төхөөмж дээрх ямар аппликешнүүд ашиглагдсан талаарх мэдээлийг олох боломжтой."</string> + <string name="permlab_startTasksFromRecents" msgid="8990073877885690623">"саяхных дотроос ажил эхлүүлэх"</string> + <string name="permdesc_startTasksFromRecents" msgid="7382133554871222235">"Апп-д ActivityManager.getRecentTaskList()-с буцаж ирсэн дууссан ажлыг эхлүүлэхийн тулд ActivityManager.RecentTaskInfo объектыг ашиглах боломж олгоно."</string> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"хэрэглэгчидтэй харилцан үйлчлэлцэх"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Апп нь төхөөрөмж дээрх ялгаатай хэрэглэгчдэд үйлдэл гүйцэтгэх боломжтой. Хортой апп нь энийг ашиглан хэрэглэгч хоорондын хамгаалалтыг зөрчих боломжтой."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"хэрэглэгчидтэй харилцан үйлчлэлцэх бүрэн зөвшөөрөл"</string> @@ -1555,7 +1557,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Блютүүт аудио"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Утасгүй дэлгэц"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Медиа гаралт"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Төхөөрөмжтэй холбох"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Дэлгэцийг төхөөрөмж рүү дамжуулах"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Төхөөрөмжүүдийг хайж байна…"</string> diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml index 30e0efbc9e15..788d8b60da18 100644 --- a/core/res/res/values-mr-rIN/strings.xml +++ b/core/res/res/values-mr-rIN/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth नकाशा संदेश प्राप्त करण्यास आणि त्यावर प्रक्रिया करण्यास अॅप ला अनुमती देते. याचा अर्थ अॅप आपल्या डिव्हाइसवर पाठविलेले संदेश आपल्याला न दर्शवता त्यांचे परीक्षण करू किंवा ते हटवू शकतो."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"चालणारे अॅप्स पुनर्प्राप्त करा"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"सध्या आणि अलीकडे चालणार्या कार्यांविषयी माहिती पुनर्प्राप्त करण्यासाठी अॅप ला अनुमती देते. हे डिव्हाइसवर कोणते अनुप्रयोग वापरले जात आहेत त्याविषयी माहिती शोधण्यासाठी अॅप ला अनुमती देऊ शकतात."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"वापरकर्त्यांशी परस्परसंवाद साधा"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"डिव्हाइसवरील भिन्न वापरकर्त्यांवर कारवाई करण्यासाठी अॅप ला अनुमती देते. दुर्भावनापूर्ण अॅप्स वापरकर्त्यांमधील संरक्षणाचे उल्लंघन करण्यासाठी हे वापरू शकतात."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"वापरकर्त्यांशी परस्परसंवाद साधण्यासाठी पूर्ण परवाना"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्टम"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडिओ"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस प्रदर्शन"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"माध्यम आउटपुट"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"डिव्हाइसला कनेक्ट करा"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"डिव्हाइसवर स्क्रीन कास्ट करा"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"डिव्हाइसेस शोधत आहे…"</string> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index fc823eea4ea0..419c9b50ade3 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Membenarkan apl menerima dan memproses mesej MAP Bluetooth. Ini bermakna apl boleh memantau atau memadam mesej yang dihantar ke peranti anda tanpa menunjukkannya kepada anda."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"dapatkan semula apl yang sedang dijalankan"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Membenarkan apl mengambil maklumat tentang tugasan yang sedang dan baru berjalan. Ini boleh membenarkan apl untuk menemui maklumat tentang apl mana yang digunakan pada peranti."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"berinteraksi sesama pengguna"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Membenarkan apl melakukan tindakan merentasi pengguna berbeza pada peranti. Apl hasad boleh menggunakan ini untuk melanggar perlindungan antara pengguna."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lesen penuh untuk berinteraksi sesama pengguna"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Membenarkan apl mengubah suai sejarah atau penanda halaman Penyemak Imbas yang tersimpan pada telefon anda. Ini boleh membenarkan apl untuk memadam atau mengubah suai data Penyemak Imbas. Nota: kebenaran ini tidak boleh dikuatkuasakan oleh penyemak imbas pihak ketiga atau aplikasi lain dengan keupayaan menyemak imbas web."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"tetapkan penggera"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Membenarkan apl untuk menetapkan penggera dalam apl penggera jam yang dipasang. Sesetengah applikasi jam penggera tidak boleh melaksanakan ciri ini."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"tulis mel suara"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Membenarkan apl mengubah suai dan mengalih keluar mesej dari peti masuk mel suara anda."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"tambah mel suara"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Membenarkan apl untuk menambahkan mesej pada peti masuk mel suara anda."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"baca mel suara"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Membenarkan apl membaca mel suara anda."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ubah suai kebenaran geolokasi Penyemak Imbas"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Membenarkan apl untuk mengubah suai kebenaran geolokasi Penyemak Imbas. Apl hasad boleh menggunakannya untuk membenarkan menghantar maklumat lokasi kepada laman web sembarangan."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"sahkan pakej"</string> @@ -1390,10 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Membenarkan aplikasi terikat kepada perkhidmatan ejen amanah."</string> <string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan kemas kini dan sistem pemulihan"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Membenarkan aplikasi berinteraksi dengan sistem pemulihan dan kemas kini sistem."</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Buat sesi unjuran media"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Membenarkan aplikasi membuat sesi unjuran media. Sesi ini boleh memberikan aplikasi keupayaan untuk mengabadikan paparan dan kandungan audio. Tidak sekali-kali diperlukan oleh apl biasa."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Sentuh dua kali untuk mendapatkan kawalan zum"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Tidak dapat menambahkan widget."</string> <string name="ime_action_go" msgid="8320845651737369027">"Pergi"</string> @@ -1518,20 +1516,14 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"Amaran penggunaan data"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"Sentuh untuk melihat penggunaan dan tetapan."</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"Data 2G-3G dimatikan"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Data 4G dimatikan"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Data selular dimatikan"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Data Wi-Fi dimatikan"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"Sudah mencapai had"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Melebihi had data 2G-3G"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Melebihi had data 4G"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Melebihi had data seluluar"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Melebihi had data Wi-Fi"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> melebihi had yang ditentukan."</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"Data latar belakang terhad"</string> @@ -1567,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Paparan wayarles"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Sambung ke peranti"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Hantar skrin ke peranti"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Mencari peranti..."</string> diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml index 46b536aae276..24be03dac6c7 100644 --- a/core/res/res/values-my-rMM/strings.xml +++ b/core/res/res/values-my-rMM/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP စာများကို app မှလက်ခံကာ အလုပ်လုပ်ရန် ခွင့်ပြင်မည်။ ဆိုလိုသည်မှာ app သည်သင့်အား မပြသဘဲ သင့်ကိရိယာသို့ပို့လိုက်သည့် စာများကို ထိန်းချုပ်နိုင် သို့မဟုတ် ဖျက်နိုင်ပါသည်။"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"အလုပ်လုပ်နေကြသည့် appများကို ရယူခြင်း"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"အပလီကေးရှင်းအား လက်ရှိနဲ့ လတ်တလော လုပ်ဆောင်ခဲ့သော သတင်းအချက်အလက် အသေးစိတ်အား ထုတ်ယူခွင့်ပြုရန်။ အပလီကေးရှင်းမှ သင် ဘယ် အပလီကေးရှင်းများသုံးရှိကြောင့် တွေ့ရှိနိုင်ပါသည်"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"အသုံးပြုသူများအကြား ဆက်ဆံခြင်း"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"အပလီကေးရှင်းအား စက်ပေါ်ရှိ တစ်ယောက်ထက်ပိုသော အသုံးပြုသူများအတွက် လုပ်ဆောင်ချက်များ ပြုလုပ်ခွင့်ပေးပါ။ အန္တရာယ်ရှိသော အပလီကေးရှင်းများမှ ဒီအရာကို သုံးပြီး အသုံးပြုသူများအတွင်း ကာကွယ်မှုကို ဖောက်ဖျက်နိုင်ပါသည်"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"အသုံးပြုသူများအကြား ဆက်ဆံရန် လိုင်စင် အပြည့်"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"စနစ်"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ဘလူးတုသ် အသံ"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"ကြိုးမဲ့ပြသခြင်း"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"မီဒီယာ အထွက်"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"စက်တစ်ခုကို ချိတ်ဆက်ရန်"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ဖန်သားပြင်ကို စက်ဆီ ပို့လွှတ်ပါ"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"စက်များကို ရှာဖွေနေပါသည် ..."</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index d8efcc6dc7d5..f1079d173f59 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Appen gis tillatelse til å motta og behandle Bluetooth MAP-meldinger. Dette betyr at appen kan overvåke eller slette meldinger som er sendt til enheten din, uten at du får se dem."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"hente apper som kjører"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Lar appen hente informasjon om oppgaver som kjører og som nylig har kjørt. Dette kan tillate appen å oppdage informasjon om hvilke apper som brukes på enheten."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"samhandling på tvers av brukere"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillater at appen utfører handlinger på tvers av ulike brukere på enheten. Skadelige apper kan utnytte dette til å bryte beskyttelsen mellom brukere."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"full lisens til å samhandle på tvers av brukere"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skjerm"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Koble til enheten"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast skjermen til enheten"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søker etter enheter …"</string> diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml index d5b152d82dfc..64d4c6231a40 100644 --- a/core/res/res/values-ne-rNP/strings.xml +++ b/core/res/res/values-ne-rNP/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"अनुप्रयोगलाई ब्लुटुथ MAP सन्देशहरू प्राप्त गर्न र प्रक्रिया गर्न अनुमति दिन्छ। यो अनुप्रयोगले तपाईँलाई नदेखाई आफ्नो उपकरणमा पठाइएको सन्देशहरू अनुगमन वा मेटाउन सक्दछ।"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"चलिरहेका अनुप्रयोगहरू पुनःबहाली गर्नुहोस्"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"वर्तमानमा र भरखरै चलिरहेका कार्यहरू बारेको सूचना पुनःबहाली गर्न अनुप्रयोगलाई अनुमित दिन्छ। यसले उपकरणमा प्रयोग भएका अनुप्रयोगहरूको बारेमा सूचना पत्ता लगाउन अनुप्रयोगलाई अनुमति दिन सक्छ।"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"प्रयोगकर्ताहरू तर्फ अन्तर्क्रिया गर्नुहोस्"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"अनुप्रयोगलाई उपकरणमा विभिन्न प्रयोगकर्ताहरू मार्फत कार्यहरू गर्न अनुमति दिन्छ। खराब अनुप्रयोगहरूले यो प्रयोगकर्ताहरू बिच सुरक्षा बिथोल्न प्रयोग गर्न सक्ने छन्।"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"कुराकानी प्रयोगकर्ताहरू बिच अन्तर्क्रिया गर्न पूर्ण अनुमति"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"तपाईँको फोनमा भण्डारण भएको ब्राउजरको इतिहास वा बुकमार्कहरू परिवर्तन गर्नको लागि अनुप्रयोगलाई अनुमति दिन्छ। यसले सायद ब्राउजर डेटालाई मेट्न वा परिवर्तन गर्नको लागि अनुप्रयोगलाई अनुमति दिन्छ। नोट: वेब ब्राउज गर्ने क्षमतासहितका अन्य अनुप्रयोगहरू वा तेस्रो- पक्ष ब्राउजरद्वारा सायद यस अनुमतिलाई लागु गर्न सकिंदैन।"</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"एउटा आलर्म सेट गर्नुहोस्"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"स्थापना गरिएको सङ्केत घडी अनुप्रयोगमा सङ्केत समय मिलाउन अनुप्रयोगलाई अनुमति दिन्छ। केही सङ्केत घडी अनुप्रयोगहरूले यो सुविधा कार्यान्वयन नगर्न सक्छन्।"</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"भ्वाइसमेलहरू लेख्नुहोस्"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"तपाईँको भ्वाइसमेल इनबक्समा सन्देश परिमार्जन गर्न र हटाउन अनुप्रयोगलाई अनुमति दिनुहोस्।"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"भ्वाइसमेल थप गर्नुहोस्"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"तपाईँको भ्वाइसमेल इनबक्समा सन्देश थप्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"भ्वाइसमेल पढ्नुहोस्"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"तपाईँको भ्वाइसमेलहरु पढ्न अनुमति दिन्छ।"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"भूस्थान अनुमतिहरू ब्राउजर परिवर्तन गर्नुहोस्"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ब्राउजरको भू-स्थान अनुमतिहरू परिमार्जन गर्न अनुप्रयोगलाई अनुमति दिन्छ। खराब अनुप्रयोगहरूले स्थान सूचना मनपरी वेब साइटहरूमा पठाउने अनुमतिको लागि यसलाई प्रयोग गर्न सक्छन्।"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"प्यकेजहरूको निरीक्षण गर्नुहोस्"</string> @@ -1399,7 +1399,7 @@ <string name="permlab_recovery" msgid="3157024487744125846">"अद्यावधिक र रिकभरी प्रणालीको साथ अन्तर्क्रिया"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"अनुप्रयोगलाई रिकभरी प्रणाली र प्रणाली अद्यावधिकहरूको साथ अन्तर्क्रिया गर्न अनुमति दिन्छ।"</string> <string name="permlab_createMediaProjection" msgid="4941338725487978112">"मिडिया प्रक्षेपण सत्रहरू सिर्जना गर्नुहोस्"</string> - <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"मिडिया प्रक्षेपण सत्र सिर्जना गर्न अनुप्रयोग लाई अनुमति दिन्छ। यी सत्रले प्रदर्शन र अडियो सामग्री खिच्ने क्षमताका अनुप्रयोगहरू प्रदान गर्न सक्छन्। सामान्य अनुप्रयोगहरूको कहिल्यै पनि आवश्यक पर्दैन।"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"मिडिया प्रक्षेपण सत्र सिर्जना गर्न अनुप्रयोगलाई अनुमति दिन्छ। यी सत्रले प्रदर्शन र अडियो सामग्री खिच्ने क्षमताका अनुप्रयोगहरू प्रदान गर्न सक्छन्। सामान्य अनुप्रयोगहरूको कहिल्यै पनि आवश्यक पर्दैन।"</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"जुम नियन्त्रणको लागि दुई चोटि टच गर्नुहोस्"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"विजेट थप गर्न सकिँदैन।"</string> <string name="ime_action_go" msgid="8320845651737369027">"जानुहोस्"</string> @@ -1528,7 +1528,7 @@ <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G डेटा बन्द छ"</string> <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"सेलुलर डेटा बन्द छ"</string> <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"वाइफाइ डेटा बन्द छ"</string> - <string name="data_usage_limit_body" msgid="6131350187562939365">"सिमा पुग्यो"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"सीमा पुग्यो"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G डेटा सीमा भन्दा पार भएको छ"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G डेटा SIMा नाघ्यो"</string> <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"सेलुलर डेटा सीमा नाघ्यो"</string> @@ -1567,7 +1567,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"प्रणाली"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ब्लुटुथ अडियो"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"ताररहित प्रदर्शन"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"मिडियाको उत्पादन"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"उपकरणमा जडान गर्नुहोस्"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"उपकरणलाई स्क्रिनमा कास्ट गर्नुहोस्"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"उपकरणको खोजी गरिँदै..."</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 7bcbbe2d31ab..8270df9569f4 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Hiermee kan de app Bluetooth MAP-berichten ontvangen en verwerken. Dit betekent dat de app berichten die naar uw apparaat zijn verzonden, kan controleren of verwijderen zonder ze aan u te laten zien."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"actieve apps ophalen"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Hiermee kan de app informatie ophalen over actieve en recent uitgevoerde taken. Zo kan de app informatie vinden over welke apps op het apparaat worden gebruikt."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interactie tussen gebruikers"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Hiermee kan de app acties uitvoeren voor verschillende gebruikers van het apparaat. Schadelijke apps kunnen dit gebruiken om de beveiliging tussen gebruikers te schenden."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"volledige toestemming voor interactie tussen gebruikers"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systeem"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Draadloze weergave"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Verbinding maken met apparaat"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Scherm casten naar apparaat"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Zoeken naar apparaten…"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 3822c4eb2cbd..4bc6541bf103 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Pozwala aplikacji na odbieranie i przetwarzanie komunikatów Bluetooth MAP. Oznacza to, że może ona bez Twojej wiedzy monitorować i usuwać komunikaty przesyłane do Twojego urządzenia."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"pobieranie uruchomionych aplikacji"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Pozwala aplikacji na pobieranie informacji o aktualnie i niedawno działających zadaniach. Dzięki temu aplikacja może uzyskać informacje o tym, które aplikacje są używane na urządzeniu."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakcje między użytkownikami"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umożliwia aplikacji wykonywanie działań dotyczących różnych użytkowników urządzenia. Złośliwe aplikacje mogą to wykorzystać do złamania zabezpieczeń na kontach użytkowników."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"pełna licencja na interakcje między użytkownikami"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Wyświetlacz bezprzewodowy"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Wyjście multimediów"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Połącz z urządzeniem"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prezentuj ekran na urządzeniu"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Szukam urządzeń…"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 5941e185cdbb..e782435b4a1f 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite à aplicação receber e processar mensagens MAP Bluetooth, o que significa que a aplicação poderá monitorizar ou eliminar mensagens enviadas para o seu dispositivo sem lhas mostrar."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"obter aplicações em execução"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite que a aplicação recupere informações acerca de tarefas executadas atual e recentemente. Isto pode permitir que a aplicação descubra informações acerca de quais as aplicações utilizadas no dispositivo."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagir entre utilizadores"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que a aplicação execute ações com diferentes utilizadores no dispositivo. Aplicações maliciosas poderão utilizar esta opção para violar a proteção entre utilizadores."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licença completa para interagir entre utilizadores"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Visualização sem fios"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de som multimédia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Ligar ao dispositivo"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir ecrã para o dispositivo"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"A pesquisar dispositivos…"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index abc0b5e8085e..114485bbfc33 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite que o aplicativo receba e processe mensagens Bluetooth MAP. Isso significa que o aplicativo pode monitorar ou excluir as mensagens enviadas para o dispositivo sem mostrá-las para você."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicativos em execução"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite que o aplicativo obtenha informações sobre tarefas em execução atuais e recentes. Pode permitir que o aplicativo descubra informações sobre os aplicativos usados no dispositivo."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagir entre os usuários"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que o aplicativo execute ações entre os diversos usuários do aparelho. Aplicativos mal-intencionados podem usar isto para violar a proteção entre os usuários."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"permissão total para interagir entre os usuários"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite que o aplicativo modifique o histórico ou os favoritos do navegador armazenados no telefone. Pode permitir que o aplicativo apague ou modifique os dados do navegador. Observação: pode não ser aplicável a navegadores de terceiros e outros aplicativos com capacidade de navegação na web."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"definir um alarme"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite que o aplicativo defina um alarme em um aplicativo despertador instalado. Alguns aplicativos despertador podem não implementar este recurso."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"gravar correio de voz"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Permite que o app modifique e remova mensagens da caixa de entrada do correio de voz."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"adicionar correio de voz"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite que o aplicativo adicione mensagens a sua caixa de entrada do correio de voz."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"ler correio de voz"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Permite que o app leia seus correios de voz."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Modifique as permissões de geolocalização de seu navegador"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite que o aplicativo modifique as permissões de geolocalização do navegador. Aplicativos maliciosos podem usar isso para permitir o envio de informações locais para sites arbitrários."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"verificar pacotes"</string> @@ -1390,10 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que o aplicativo se associe a um serviço de agente de confiança."</string> <string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de atualizações e recuperação"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Permite que um aplicativo interaja com o sistema de recuperação e as atualizações do sistema."</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Criar sessões de projeção de mídia"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Permite que um aplicativo crie sessões de projeção de mídia. As sessões podem fornecer aos aplicativos a capacidade de capturar conteúdo de tela e de áudio. Isso nunca deve ser necessário em aplicativos normais."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toque duas vezes para controlar o zoom"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Não foi possível adicionar widget."</string> <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string> @@ -1518,20 +1516,14 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"Toque p/ ver uso e config."</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"Os dados 2G-3G foram desativados"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Os dados 4G foram desativados"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Dados da rede cel. desativados"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Os dados Wi-Fi foram desativados"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"Limite atingido"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Limite de dados 2G-3G excedido"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Limite de dados 4G excedido"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Lim. de dados rede cel. excedido"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Limite de dados Wi-Fi excedido"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> acima do limite especificado."</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"Dados de segundo plano restritos"</string> @@ -1567,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Display sem fio"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar ao dispositivo"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir tela para dispositivo"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Procurando dispositivos…"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index f1a4b9644973..84413bbe4aec 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite aplicației să primească și să proceseze mesaje MAP prin Bluetooth. Aceasta înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitiv fără a le afișa."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"preluare aplicaţii care rulează"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicaţiei să preia informaţiile despre activităţile care rulează în prezent şi care au rulat recent. În acest fel, aplicaţia poate descoperi informaţii despre aplicaţiile care sunt utilizate pe dispozitiv."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interacţiune între utilizatori"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite aplicaţiei să efectueze acţiuni pentru diferiţi utilizatori pe dispozitiv. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a încălca protecţia între utilizatori."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licenţă completă pentru interacţiune între utilizatori"</string> @@ -719,8 +723,8 @@ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"conectare la un serviciu furnizor de condiții"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu furnizor de condiții. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> - <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"conectare la un serviciu de trasee multimedia"</string> - <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de trasee multimedia. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> + <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"se conectează la un serviciu de trasee multimedia"</string> + <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite deținătorului să se conecteze la interfața de nivel superior a unui serviciu de trasee multimedia. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="permlab_bindDreamService" msgid="4153646965978563462">"se conectează la un serviciu de vis"</string> <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite deținătorului să se conecteze la interfața superioară a unui serviciu de vis. Această opțiune nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"apelarea aplicației de configurare furnizată de operator"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicaţiei să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicaţia poate şterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicaţii cu capacităţi de navigare pe web."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"setează o alarmă"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicaţiei să seteze o alarmă într-o aplicaţie de ceas cu alarmă instalată. Este posibil ca unele aplicaţii de ceas cu alarmă să nu implementeze această funcţie."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"scrierea mesajelor vocale"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Permite aplicației să modifice și să elimine mesaje din secțiunea de mesaje vocale primite."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite aplicaţiei să adauge mesaje în Mesaje primite în mesageria vocală."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"citirea mesajelor vocale"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Permite aplicației să citească mesajele vocale."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modificare permisiuni pentru locaţia geografică a browserului"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite aplicaţiei să modifice permisiunile privind locaţia geografică a browserului. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a permite trimiterea informaţiilor privind locaţia către site-uri web arbitrare."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"verificare pachete"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Ecran wireless"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectați-vă la dispozitiv"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Proiectați ecranul pe dispozitiv"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Se caută dispozitive..."</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index d74a21514a55..99a7c13c4857 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Получение и обработка сообщений Bluetooth MAP. Отслеживание и удаление непрочитанных сообщений."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"Получение данных о запущенных приложениях"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Приложение сможет получать информацию о недавно запущенных и выполняемых задачах, а следовательно, и о приложениях, используемых на устройстве."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Взаимодействие с аккаунтами всех пользователей"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Приложение сможет выполнять действия во всех аккаунтах на этом устройстве. При этом защита от вредоносных приложений может быть недостаточной."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Полное взаимодействие с аккаунтами всех пользователей"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Приложение сможет изменять историю или закладки браузера, сохраненные на телефоне, а также удалять и изменять данные браузера. Обратите внимание: браузеры независимых поставщиков или другие приложения для просмотра веб-страниц могут не применять это разрешение."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"Установка будильника"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Приложение сможет настраивать будильник. Функция поддерживается не во всех программах."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"запись голосовых сообщений"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Изменение и удаление сообщений из голосовой почты."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"Добавление голосовых сообщений"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Приложение сможет добавлять голосовые сообщения в папку \"Входящие\"."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"чтение голосовых сообщений"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Доступ к голосовой почте."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Изменение прав доступа к геоданным в браузере"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Приложение сможет изменять настройки доступа к геоданным в браузере. Вредоносные программы смогут таким образом отправлять информацию о местоположении на любые веб-сайты."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"Проверка пакетов"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Беспроводной монитор"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Подключение к устройству"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Подключение к удаленному дисплею"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Поиск устройств…"</string> diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml index 38b153dc6e28..b8622a59e61e 100644 --- a/core/res/res/values-si-rLK/strings.xml +++ b/core/res/res/values-si-rLK/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"බ්ලූටූත් MAP පණිවිඩ සොයා ලබාගැනීමට සහ ක්රියාත්මක කිරීමට යෙදුමට අවසර දෙන්න. යෙදුම නිරීක්ෂණය කරනු ලබන අතර ඔබට ලැබුන පණිවිඩ පෙන්වීමෙන් තොරවම මකා දැමිය හැකි බව මෙමඟින් අදහස් කරයි."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"ධාවනය වන යෙදුම් ලබාගැනීම"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"දැනට සහ මෑත ක්රියාත්මක කාර්යයන් පිළිබඳ විස්තරාත්මක තොරතුරු සොයා ලබාගැනීමට යෙදුමට ඉඩ දෙන්න. මෙය කුමන යෙදුම් උපාංගයේ භාවිතා කරන්නේද යන තොරතුරු යෙදුම්වලට සොයා ගැනීමට ඉඩ දිය හැක."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"පරිශීලකයන් අතර අන්තර්ක්රියාකාරී වන්න"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"උපාංගයේ විවිධ පරිශීලකයන් හරහා ක්රියාවන් දැක්වීමට යෙදුමට අවසර දෙන්න. පරිශීලකයන් අතර ආරක්ෂාව කඩකිරීමට අනිෂ්ට යෙදුම් විසින් මෙය භාවිතා කිරීමට ඉඩ ඇත."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"පරිශීලකයන් අතර අන්තර් ක්රියාකාරී වීමට සම්පූර්ණ බලපත්රය"</string> @@ -1008,16 +1012,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ඔබගේ දුරකථනයේ ආචයනය කරන ලද බ්රව්සර ඉතිහාසය හෝ පිටුසන වෙනස් කිරීමට යෙදුමට අවසර දෙන්න. ඔබගේ බ්රව්සර දත්ත මැකීමට හෝ වෙනස් කිරීමට අනිෂ්ට යෙදුම් මෙය භාවිත කරයි. සටහන: වෙබ් බ්රව්සර අවශ්යතාවය සමග තෙවෙනි පාර්ශව බ්රව්සර හෝ වෙනත් යෙදුම් විසින් මෙම අවසරය බල ගැන්විය හැක."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"සීනුවක් සැකසීම"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"ස්ථාපනය කරන ලද සීනු ඔරලෝසු යෙදුමේ සීනුව සකස් කරන්නට යෙදුමට ඉඩ දෙන්න. ඇතැම් සීනු ඔරලෝසු යෙදුම් මෙම අංගය ක්රියාවට නංවා නොතිබීමට ඉඩ තිබේ."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"හඬ තැපෑල් ලියන්න"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"ඔබගේ හඬ තැපෑලේ එන ලිපි වෙත එන පණිවිඩ ඉවත් කිරීමට යෙදුමට අවසර දෙන්න."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"හඬ තැපෑල එක් කිරීම"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ඔබගේ හඬ තැපෑලේ එන ලිපි වෙත එන පණිවිඩ එකතු කිරීමට යෙදුමට අවසර දෙන්න."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"හඬ තැපෑල් කියන්න"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"ඔබගේ හඬ තැපැල් කියවීමට යෙදුමට අවසර දේ."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"බ්රව්සරයේ භූ අවසර වෙනස් කිරීම"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"බ්රවුසරයේ භූ ස්ථානීය අවසර වෙනස් කිරීමට යෙදුමට අවසර දෙන්න. අභිමත වෙබ් අඩවි වලට ස්ථානීය තොරතුරු යැවීමට අනිෂ්ට යෙදුම් මෙය භාවිතා කෙරේ."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"පැකේජ සත්යාපනය කරන්න"</string> @@ -1393,10 +1393,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"යෙදුමකට විශ්වාසනීය ඒජන්ත සේවාවකට බැඳීමට අවසර දේ."</string> <string name="permlab_recovery" msgid="3157024487744125846">"ප්රතිසාධන පද්ධතිය සහ යාවත්කාලීන සමඟ කටයුතු කරන්න"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"යෙදුමකට ප්රතිසාධන පද්ධතිය සහ පද්ධති යාවත්කාලීන සමඟ කටයුතු කිරීමට ඉඩ දෙන්න."</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"මාධ්ය ප්රක්ෂේපන සැසියන් සාදන්න"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"මාධ්ය ප්රක්ෂේපන සැසියන් සාදන්න යෙදුමට ඉඩ දෙන්න. ශ්රව්ය අන්තර්ගතයන් සහ දර්ශන ලබා ගැනීමට හැකියාව යෙදුම් වලට මෙම සැසියන් ලබාගත හැක. සමාන්ය යෙදුම් සඳහා කවදාවත් අවශ්ය නොවේ."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"විශාලන පාලනය සඳහා දෙවරක් ස්පර්ශ කරන්න"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"විජටය එකතු කිරීමට නොහැකි විය."</string> <string name="ime_action_go" msgid="8320845651737369027">"යන්න"</string> @@ -1521,20 +1519,14 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය කරන්න"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"දත්ත භාවිතා අවවාදය"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"භාවිතය සහ සැකසීම් බැලීමට ස්පර්ශ කරන්න."</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G දත්ත නැත"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G දත්ත නැත"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"සෙලියුලර් දත්ත අක්රියයි"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi දත්ත අක්රියයි"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"සීමාව ළඟාවී ඇත"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G දත්ත සීමාව ඉක්මවන ලදි"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G දත්ත සීමාව ඉක්මවා යන ලදි"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"සෙලියුලර් දත්ත සීමාව ඉක්මවා තිබේ"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi දත්ත සීමාව ඉක්මවා යන ලදි"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"සඳහන් කළ සීමාවට වඩා <xliff:g id="SIZE">%s</xliff:g> වැඩිය."</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"පසුබිම් දත්ත සිමා කරන ලදි"</string> @@ -1570,7 +1562,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"පද්ධතිය"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"බ්ලූටූත් ශ්රව්ය"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"රැහැන් රහිත දර්ශනය"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"මාධ්ය ප්රතිදානය"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"උපාංගයට සම්බන්ධ වන්න"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"තිරය උපාංගයට යොමු කරන්න"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"උපාංග සඳහා සොයමින්…"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 63bb72b65150..fdfcd8277223 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Umožňuje aplikácii prijímať a spracovávať správy MAP rozhrania Bluetooth. Znamená to, že aplikácia môže sledovať správy odoslané na vaše zariadenie alebo ich odstrániť bez toho, aby sa vám zobrazili."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"načítať spustené aplikácie"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Umožňuje aplikácii načítať informácie o aktuálne či nedávno spustených úlohách. Toto povolenie môže aplikácii umožniť objaviť informácie o tom, ktoré aplikácie sa na zariadení používajú."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakcie naprieč používateľmi"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umožňuje aplikácii vykonávať akcie naprieč rôznymi používateľmi zariadenia. Škodlivé aplikácie môžu toto povolenie zneužiť na obídenie ochrany medzi používateľmi."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"plná licencia na interakcie naprieč používateľmi"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Umožňuje aplikácii upraviť históriu prehliadača alebo záložky uložené v telefóne. Aplikácia s týmto povolením môže vymazať alebo upraviť údaje prehliadača. Poznámka: Toto povolenie nemôžu vynucovať prehliadače tretích strán ani žiadne ďalšie aplikácie umožňujúce prehliadanie webu."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"nastaviť budík"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Umožňuje aplikácii nastaviť budík v nainštalovanej aplikácii budík. Niektoré aplikácie budíka nemusia túto funkciu implementovať."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"zapisovanie do hlasovej schránky"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Povoľuje aplikácii upravovať a odstraňovať správy z hlasovej schránky."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"pridať hlasovú schránku"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Umožní aplikácii pridávať správy do doručenej pošty hlasovej schránky."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"čítanie hlasových správ"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Umožňuje aplikácii čítať vaše hlasové správy."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"zmeniť povolenia prehliadača poskytovať informácie o zemepisnej polohe"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Umožňuje aplikácii zmeniť povolenia prehliadača na poskytovanie údajov o zemepisnej polohe. Škodlivé aplikácie to môžu použiť na odosielanie informácií o polohe ľubovoľným webovým stránkam."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"overiť balíky"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrôtový displej"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Pripojenie k zariadeniu"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prenos obraz. do zariad."</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Prebieha vyhľadávanie zariadení…"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index cda7606ffe3a..2cd858e86321 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Aplikaciji omogoča prejemanje in obdelavo sporočil Bluetooth MAP. To pomeni, da lahko aplikacija nadzira in izbriše sporočila, poslana v napravo, ne da bi vam jih prikazala."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"dobivanje programov, ki se izvajajo"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Aplikaciji omogoča prejemanje podatkov o trenutnih in nedavno izvajajočih se opravilih. S tem lahko aplikacija odkrije podatke o aplikacijah, ki se uporabljajo v napravi."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakcija z uporabniki"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Aplikaciji omogoča izvajanje dejanj za različne uporabnike v napravi. Zlonamerne aplikacije lahko to uporabijo za kršitev zaščite med uporabniki."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"polna licenca za interakcijo z uporabniki"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Aplikaciji omogoča spreminjanje zgodovine ali zaznamkov brskalnika v telefonu. S tem lahko aplikacija izbriše ali spremeni podatke v brskalniku. Opomba: Tega dovoljenja ne morejo uveljavljati drugi brskalniki ali aplikacije, s katerimi je mogoče brskati po spletu."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"nastavitev alarma"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Programu omogoča nastavitev alarma v nameščenem programu budilke. Nekateri programi budilke morda nimajo te funkcije."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"snemanje sporočil v odzivniku"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Aplikaciji omogoča spreminjanje in odstranjevanje sporočil iz odzivnika."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"dodajanje odzivnika"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Programu omogoča dodajanje sporočil prejetim sporočilom odzivnika."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"branje sporočil v odzivniku"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Aplikaciji omogoča branje sporočil v odzivniku."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Spreminjanje dovoljenj za geolokacijo brskalnika"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Programu omogoča spreminjanje geolokacijskih dovoljenj v brskalniku. Zlonamerni programi lahko to izkoristijo za pošiljanje podatkov o lokaciji poljubnim spletnim mestom."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"preveri pakete"</string> @@ -1516,10 +1516,10 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"Opozorilo o uporabi podatkov"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"Dotaknite se za uporabo in nast."</string> - <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"Prenos pod. v omr. 2G/3G je izk."</string> - <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Prenos pod. v omrež. 4G je izkl."</string> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"Podatki v omrežju 2G/3G so izkl."</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Podatki v omrežju 4G so izklop."</string> <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Prenos mob. podatkov izklopljen"</string> - <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Prenos pod. v om. Wi-Fi je izkl."</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Prenos pod. prek Wi-Fi je izkl."</string> <string name="data_usage_limit_body" msgid="6131350187562939365">"Omejitev je dosežena"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Omejit. za podat. 2G-3G presež."</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Omejitev za podat. 4G presež."</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Brezžični prikaz"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Izhod predstavnosti"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Povezovanje z napravo"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Predvajanje zaslona v napravi"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Iskanje naprav …"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index c23481872178..25bf1a949269 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Дозвољава апликацији да прима и обрађује Bluetooth MAP поруке. То значи да апликација може да надгледа или брише поруке које се шаљу на уређај, а да вам их не прикаже."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"преузимање покренутих апликација"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Дозвољава апликацији да преузима информације о актуелним и недавно покренутим задацима. Ово може да омогући апликацији да открије информације о томе које се апликације користе на уређају."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"интеракција између корисника"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Дозвољава апликацији да обавља радње између различитих корисника на уређају. Злонамерне апликације могу да користе ово да би угрозиле заштиту између корисника."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"пуна лиценца за интеракцију између корисника"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Бежични екран"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Излаз медија"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Повежите са уређајем"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Пребаците екран на уређај"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Тражење уређаја…"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 913bc909f29a..7eee11bd79ee 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Tillåter att appen tar emot och hanterar Bluetooth MAP-meddelanden. Detta innebär att appen kan övervaka eller ta bort meddelanden som skickats till enheten utan att visa dem för dig."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"hämta appar som körs"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Tillåter att appen hämtar information om nyligen körda och pågående aktiviteter. Detta kan innebära att appen tillåts ta reda på vilka appar som används på enheten."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagera mellan användare"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillåter att appen utför åtgärder mellan användare på enheten. Skadliga appar kan använda detta som ett sätt att kringgå skyddet mellan användare."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"fullständig behörighet att interagera mellan användare"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådlös skärm"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieuppspelning"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Anslut till enhet"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Överför skärmen till enheten"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Söker efter enheter ..."</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index acbef24cf3f7..a00ea1686cdc 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Inaruhusu programu kupokea na kuchakata ujumbe wa Bluetooth MAP. Hii inamaanisha programu inaweza kufuatilia au kufuta ujumbe unaotumwa kwenye kifaa chako pasipo kukuonyesha ujumbe huo."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"rudisha programu zinazoendeshwa"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Inaruhusu programu kurudisha taarifa kuhusu kazi zinazoendeshwa sasa na hivi karibuni. Hii inaweza kuruhusu programu kugundua taarifa kuhusu ni programu zipi zinazotumika kwenye kifaa."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kuwasiliana na watumiaji wengine"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Inaruhusu programu kutenda vitendo kwa watumiaji tofauti kwenye kifaa. Programu hasidi huenda zikatumia hii ili kukiuka ulinzi kati ya watumiaji."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"leseni kamili ili kushirikiana na watumiaji"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Inaruhusu programu kurekebisha historia ya Kivinjari au alamisho zilizohifadhiwa kwenye simu yako. Hii huenda ikaruhusu programu kufuta au kurekebisha data ya Kivinjari. Kumbuka: huenda idhini hii isitekelezwe na vivinjari vingine au programu nyingine zenye uwezo wa kuvinjari wavuti."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"weka kengele"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Inaruhusu programu kuweka kengele katika programu iliyosakinishwa ya kengele. Programu zingine za kengele zinawezakosa kutekeleza kipengee hiki."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"andika ujumbe wa sauti"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Huruhusu programu kubadili na kuondoa ujumbe kwenye kikasha chako cha ujumbe wa sauti."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"ongeza barua ya sauti"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Huruhusu programu kuongeza mawasiliano kwenye kikasha cha ujumbe wa sauti."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"soma ujumbe wa sauti"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Huruhusu programu isome ujumbe wako wa sauti."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Rekebisha vibali vya Kivinjari cha eneo la jio"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Inaruhusu programu kurekebisha ruhusa za eneo la jio za kivinjari. Programu hasidi zinaweza tumia hii kuruhusu kutuma taarifa ya eneo kwa wavuti holela."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"thibitisha furushi"</string> @@ -1523,7 +1523,7 @@ <string name="data_usage_limit_body" msgid="6131350187562939365">"Kikomo kimefikiwa"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Kikomo cha data ya 2G-3G kimezidishwa"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Kikomo cha data cha 4G kimezidishwa"</string> - <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Kikomo cha data ya simu za mkononi kimevukwa"</string> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Umezidi kikomo cha data ya simu"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Taarifa za Wi-fi zimevuka kiwanga"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> juu ya kikomo kilichobainishwa."</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"Data ya mandhari nyuma imezuiwa"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Uonyeshaji usiotumia waya"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Towe la midia"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Unganisha kwenye kifaa"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Tuma skrini kwenye kifaa"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Inatafuta vifaa..."</string> diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml index eacc824d0dca..7d4478e10f8d 100644 --- a/core/res/res/values-ta-rIN/strings.xml +++ b/core/res/res/values-ta-rIN/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"புளூடூத் MAP செய்திகளைப் பெற மற்றும் செயல்படுத்த பயன்பாட்டை அனுமதிக்கிறது. அதாவது பயன்பாட்டால் சாதனத்திற்கு அனுப்பப்பட்ட செய்திகளை, உங்களிடம் காட்டாமலே கண்காணிக்கவோ, நீக்கவோ முடியும்."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"இயங்கும் பயன்பாடுகளை மீட்டெடுத்தல்"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"நடப்பில் மற்றும் சமீபத்தில் இயங்கும் காரியங்களின் தகவலைப் பெற பயன்பாட்டை அனுமதிக்கிறது. சாதனத்தில் எந்தப் பயன்பாடுகள் பயன்படுத்தப்படுகின்றன என்பது குறித்த தகவலைக் கண்டறிய பயன்பாட்டை இது அனுமதிக்கலாம்."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"பிற பயனர்களுடன் தொடர்புகொள்ளுதல்"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"சாதனத்தில் உள்ள பல்வேறு பயனர்கள் அனைவரிலும் செயல்களைச் செய்ய பயன்பாட்டை அனுமதிக்கிறது. பயனர்கள் இடையேயான பாதுகாப்பை மீற தீங்கிழைக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"பிற பயனர்களுடன் தொடர்புகொள்வதற்கான முழு உரிமம்"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"அமைப்பு"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"புளூடூத் ஆடியோ"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"வயர்லெஸ் காட்சி"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"மீடியா வெளியீடு"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"சாதனத்துடன் இணைக்கவும்"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"திரையிலிருந்து சாதனத்திற்கு அனுப்புக"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"சாதனங்களைத் தேடுகிறது..."</string> diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml index b373cc7d5f78..18688180221c 100644 --- a/core/res/res/values-te-rIN/strings.xml +++ b/core/res/res/values-te-rIN/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"బ్లూటూత్ MAP సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. అనువర్తనం మీ పరికరానికి పంపబడిన సందేశాలను పర్యవేక్షించగలదని లేదా మీకు చూపకుండానే తొలగించగలదని దీనర్థం."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"అమలవుతున్న అనువర్తనాలను పునరుద్ధరించడం"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"ప్రస్తుతం మరియు ఇటీవల అమలవుతున్న విధుల గురించి వివరణాత్మక సమాచారాన్ని తిరిగి పొందడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఇది పరికరంలో ఉపయోగించబడిన అనువర్తనాల గురించి సమాచారాన్ని కనుగొనడానికి అనువర్తనాన్ని అనుమతించవచ్చు."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"వినియోగదారుల మధ్య పరస్పర చర్య చేయడం"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"పరికరంలోని విభిన్న వినియోగదారుల తరపున చర్యలను అమలు చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. హానికరమైన అనువర్తనాలు వినియోగదారుల మధ్య రక్షణను ఉల్లంఘించడానికి దీన్ని ఉపయోగించవచ్చు."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"వినియోగదారుల మధ్య పరస్పర చర్య చేయడానికి పూర్తి లైసెన్స్"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"సిస్టమ్"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"బ్లూటూత్ ఆడియో"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"వైర్లెస్ డిస్ప్లే"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"మీడియా అవుట్పుట్"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"పరికరానికి కనెక్ట్ చేయండి"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"స్క్రీన్ను పరికరానికి ప్రసారం చేయండి"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"పరికరాల కోసం శోధిస్తోంది…"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 31ad7645af2f..a5d7a36e7811 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -162,7 +162,7 @@ <string name="silent_mode_silent" msgid="319298163018473078">"ปิดเสียง"</string> <string name="silent_mode_vibrate" msgid="7072043388581551395">"เสียงเรียกเข้าแบบสั่น"</string> <string name="silent_mode_ring" msgid="8592241816194074353">"เปิดเสียง"</string> - <string name="shutdown_progress" msgid="2281079257329981203">"กำลังปิดระบบ..."</string> + <string name="shutdown_progress" msgid="2281079257329981203">"กำลังปิด..."</string> <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"แท็บเล็ตของคุณจะปิดการทำงาน"</string> <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"นาฬิกาจะปิดการทำงาน"</string> <string name="shutdown_confirm" product="default" msgid="649792175242821353">"โทรศัพท์ของคุณจะปิดเครื่อง"</string> @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"อนุญาตให้แอปรับและประมวลผลข้อความ MAP สำหรับบลูทูธ ซึ่งหมายความว่าแอปจะสามารถตรวจสอบหรือลบข้อความที่ส่งไปยังอุปกรณ์ของคุณได้โดยไม่ต้องแสดงให้คุณเห็น"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"เรียกแอปพลิเคชันที่ทำงานอยู่"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"อนุญาตให้แอปพลิเคชันเรียกดูข้อมูลเกี่ยวกับงานที่ดำเนินการอยู่ในขณะนี้และเมื่อเร็วๆ นี้ ซึ่งอาจทำให้แอปพลิเคชันสามารถค้นข้อมูลได้ว่าอุปกรณ์นี้ใช้แอปพลิเคชันใดบ้าง"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"โต้ตอบระหว่างผู้ใช้"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"อนุญาตให้แอปพลิเคชันทำงานได้กับผู้ใช้หลายรายบนอุปกรณ์นี้ แอปพลิเคชันที่เป็นอันตรายอาจใช้การทำงานนี้ในการบุกรุกการป้องกันระหว่างผู้ใช้"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ใบอนุญาตฉบับเต็มสำหรับการโต้ตอบระหว่างผู้ใช้"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"ระบบ"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"การแสดงผลแบบไร้สาย"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"เอาต์พุตสื่อ"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"เชื่อมต่อกับอุปกรณ์"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ส่งหน้าจอไปยังอุปกรณ์"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"กำลังค้นหาอุปกรณ์…"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 36990ee14292..bb74ca3f49c3 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Pinapayagan ang app na makatanggap at makapagproseso ng mga mensahe ng Bluetooth MAP. Nangangahulugan ito na maaaring subaybayan o i-delete ng app ang mga mensaheng ipinapadala sa iyong device nang hindi ipinapakita ang mga ito sa iyo."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"bawiin ang tumatakbong apps"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Pinapayagan ang app na kumuha ng impormasyon tungkol sa mga kasalukuyan at kamakailang gumaganang gawain. Maaari nitong payagan ang app na tumuklas ng impormasyon tungkol sa kung aling mga application ang ginagamit sa device."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"makipag-ugnayan sa kabuuan ng mga user"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Binibigyang-daan ang app upang magsagawa ng mga pagkilos sa kabuuan ng iba\'t ibang mga user sa device. Maaari itong gamitin ng nakakahamak na apps upang lumabag sa proteksyon sa pagitan ng mga user."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ganap na lisensya upang makipag-ugnayan sa kabuuan ng mga user"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Output ng media"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Kumonekta sa device"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"I-cast ang screen sa device"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Naghahanap ng mga device…"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 3f79c6184825..927e7cbe9a4f 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Uygulamanın Bluetooth MAP iletilerini alıp işlemesine izin verir. Bu izin, uygulamanın cihazınıza gönderilen iletileri izleyebileceği veya size göstermeden silebileceği anlamına gelir."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"çalışan uygulamaları al"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Uygulamaya o anda ve son çalışan görevler hakkında bilgi alma izni verir. Bu izin, uygulamanın cihaz tarafından kullanılan uygulamalar hakkında bilgi elde etmesine olanak sağlayabilir."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kullanıcılar arasında etkileşim kurma"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Uygulamaya cihazdaki farklı kullanıcılar arasında işlem gerçekleştirme izni verir. Kötü amaçlı uygulamalar bu izinle kullanıcılar arasındaki korumayı ihlal edebilir."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"kullanıcılar arasında etkileşim kurmak için tam izin"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Uygulamaya Tarayıcı geçmişini ve telefonunuzda depolanan yer işaretlerini değiştirme izni verir. Bu izin, uygulamanın Tarayıcı geçmişini silmesine ve değiştirmesine olanak sağlar. Not: Bu izin, üçüncü taraf cihazlar veya Web\'e göz atma işlevine sahip diğer uygulamalar tarafından kullanılmayabilir."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"alarm ayarla"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Uygulamaya, çalar saat uygulamasının alarmını ayarlama izni verir. Bazı çalar saat uygulamaları bu özelliği uygulayamayabilir."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"sesli mesaj yaz"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Uygulamanın sesli mesaj gelen kutunuzdaki mesajları değiştirmesine ve kaldırmasına izin verir."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"sesli mesaj ekle"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Uygulamaya, sesli mesaj gelen kutunuza mesaj ekleme izni verir."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"sesli mesaj oku"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Uygulamanın sesli mesajlarınızı okumasına izin verir."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Tarayıcı\'nın coğrafi konum izinlerini değiştir"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Uygulamaya, Tarayıcı\'nın coğrafi konum izinlerini değiştirme izni verir. Kötü amaçlı uygulamalar keyfi web sitelerine konum bilgisi gönderilmesini sağlamak için bunu kullanabilirler."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"paketleri doğrula"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Kablosuz ekran"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Cihaza bağlanın"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekranı cihaza yayınlayın"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Cihaz aranıyor…"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index ac415eb0a649..3a217be60760 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Дозволяє додаткові отримувати й обробляти повідомлення Bluetooth MAP. Це означає, що додаток може відстежувати чи видаляти повідомлення, надіслані на ваш пристрій, навіть не показуючи їх вам."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"отримувати запущені програми"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Дозволяє програмі отримувати інформацію про поточні й останні запущені завдання. Це може дозволити програмі виявляти інформацію про програми, які використовуються на пристрої."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"взаємодіяти між користувачами"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Дозволяє програмі виконувати дії щодо різних користувачів на пристрої. Шкідливі програми можуть використовувати це для порушення захисту окремих користувачів."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"повна ліцензія на взаємодію між користувачами"</string> @@ -1386,8 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозволяє додатку прив’язуватися до служби довірчих агентів."</string> <string name="permlab_recovery" msgid="3157024487744125846">"Взаємодіяти з оновленнями системи та системою відновлення."</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Дозволяє додатку взаємодіяти із системою відновлення й оновленнями системи."</string> - <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Створювати сеанси проектування медіа"</string> - <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Додаток може створювати сеанси проектування медіа. Під час цих сеансів додатки зможуть збирати аудіовміст і вміст дисплея. Не використовується звичайними додатками."</string> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Створювати сеанси трансляції вмісту"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Додаток може створювати сеанси трансляції вмісту. Під час цих сеансів додаток зможе отримати доступ до аудіо й зображення на екрані. Не використовується звичайними додатками."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двічі торкніться, щоб керувати масштабом"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Не вдалося додати віджет."</string> <string name="ime_action_go" msgid="8320845651737369027">"Йти"</string> @@ -1516,7 +1520,7 @@ <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Дані 4G вимкнено"</string> <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Мобільні дані вимкнено"</string> <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Дані Wi-Fi вимкнено"</string> - <string name="data_usage_limit_body" msgid="6131350187562939365">"Досягнуто ліміту"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"Перевищено ліміт"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Перевищено ліміт даних 2G–3G"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Перевищено ліміт даних 4G"</string> <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Перевищено ліміт мобільних даних"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудіо Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Бездротовий екран"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Вивід медіа-даних"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Під’єднатися до пристрою"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Транслювати екран на пристрій"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Пошук пристроїв…"</string> diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml index c3feb4c33374..216a72600718 100644 --- a/core/res/res/values-ur-rPK/strings.xml +++ b/core/res/res/values-ur-rPK/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ایپ کو بلوتوٹھ MAP پیغامات وصول اور ان پر کارروائی کرنے کی اجازت دیتی ہے۔ اس کا مطلب یہ ہے کہ ایپ آپ کے آلہ پر ارسال کردہ پیغامات آپ کو دکھائے بغیر ان پر نگاہ رکھ یا انہیں حذف کرسکتی ہے۔"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"چل رہی ایپس کی بازیافت کریں"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"ایپ کو موجودہ اور حالیہ چل رہے ٹاسکس کے بارے میں معلومات بازیافت کرنے کی اجازت دیتا ہے۔ یہ ایپ کو اس بارے میں معلومات دریافت کرنے کی اجازت دے سکتا ہے کہ آلہ پر کون سی ایپلیکیشنز استعمال کی جاتی ہیں۔"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"سبھی صارفین کے ساتھ تعامل کریں"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ایپ کو آلے پر موجود مختلف صارفین کے بیچ کارروائیاں انجام دینے کی اجازت دیتا ہے۔ نقصان دہ ایپس صارفین کے مابین تحفظ کی خلاف ورزی کرنے کیلئے اسے استعمال کرسکتی ہیں۔"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"سبھی صارفین کے ساتھ تعامل کرنے کیلئے مکمل لائسنس"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ایپ کو آپ کے فون پر اسٹور کردہ براؤزر کی سرگزشت یا بک مارکس میں ترمیم کرنے کی اجازت دیتا ہے۔ یہ ایپ کو براؤزر کا ڈیٹا مٹانے یا اس میں ترمیم کرنے کی اجازت دے سکتا ہے۔ نوٹ: یہ اجازت تیسرے فریق کے براؤزرز یا ویب براؤزنگ کی لیاقتوں والی دیگر ایپلیکیشنز کے ذریعہ نافذ نہیں کی جاسکتی ہے۔"</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"ایک الارم سیٹ کریں"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"ایپ کو ایک انسٹال کردہ الارم گھڑی کی ایپ میں ایک الارم سیٹ کرنے کی اجازت دیتا ہے۔ الارم گھڑی کی کچھ ایپس اس خصوصیت کو نافذ نہیں کر سکتی ہیں۔"</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"صوتی میلز لکھیں"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"ایپ کو پیغامات میں ترمیم کرنے اور ان کو آپ کے صوتی میل ان باکس سے ہٹانے کی اجازت دیتا ہے۔"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"صوتی میل شامل کریں"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ایپ کو آپ کے صوتی میل کے ان باکس میں پیغامات شامل کرنے کی اجازت دیتا ہے۔"</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"صوتی میل پڑھیں"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"اپنے صوتی میلز پڑھنے کیلئے ایپ کو اجازت دیتا ہے۔"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"براؤزر کی جغرافیائی مقام کی اجازتوں میں ترمیم کریں"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ایپ کو براؤزر کی جغرافیائی مقام کی اجازتوں میں ترمیم کرنے کی اجازت دیتا ہے۔ نقصان دہ ایپس متنازعہ ویب سائٹس پر مقام کی معلومات بھیجنے کی اجازت دینے کیلئے اس کا استعمال کر سکتی ہیں۔"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"پیکیجز کی توثیق کریں"</string> @@ -1559,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"سسٹم"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوٹوتھ آڈیو"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"وائرلیس ڈسپلے"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"میڈیا آؤٹ پٹ"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"آلہ سے مربوط ہوں"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"اسکرین کو آلہ پر کاسٹ کریں"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"آلات تلاش کر رہا ہے…"</string> diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml index c3e7f5985a89..fb0b55fcc4bb 100644 --- a/core/res/res/values-uz-rUZ/strings.xml +++ b/core/res/res/values-uz-rUZ/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP xabarlarni qabul qilish va qayta ishlash. O‘qilmagan xabarlarni kuzatish va o‘chirish."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"ishlab turgan ilovalar to‘g‘risida ma’lumot olish"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Ilovaga hozirda va so‘nggi ishga tushirilgan vazifalar haqida to‘liq ma’lumot olishiga ruxsat beradi. Bu ilovaga qurilmadagi ishlatilayotgan ilovalar haqidagi ma’lumotlarga ega bo‘lishiga ruxsat berishi mumkin."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"foydalanuvchilar o‘rtasida o‘zaro aloqa"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ilovaga qurilmadagi turli foydalanuvchilarga ta‘sir ko‘rsatadigan amallarni bajarishga ruxsat beradi. Zararli ilovalar bundan foydalanuvchilar o‘rtasidagi himoyani buzishda foydalanishi mumkin."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"foydalanuvchilar o‘rtasidagi o‘zaro aloqa uchun to‘liq litsenziya"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Ilovaga telefoningizga zaxiralangan brauzer tarixi yoki xatcho‘plarini o‘zgartirish uchun ruxsat beradi. Bu ilovaga brauzer ma’lumotlarini o‘zgartirish yoki o‘chirishga ruxsat berishi mumkin. Diqqat qiling: ushbu ruxsat uchinchi taraf brauzerlari yoki internetni ko‘rsatish qobiliyatiga ega boshqa ilovalardan talab qilinmasligi mumkin."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"signal o‘rnatish"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Ilova uyg‘otkichni sozlashi mumkin. Ba’zi soat ilovalari ushbu funksiyani qo‘llab-quvvatlamasligi mumkin."</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"ovozli pochta xabarlarini yozish"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Ilovaga ovozli pochtangizdagi xabarlarni o‘zgartirish va o‘chirish uchun ruxsat beradi."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"ovozli xat qo‘shish"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Ilova xabarlarni ovozli pochta qutingizga qo‘shishi mumkin."</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"ovozli pochta xabarlarini o‘qish"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Ilovaga ovozli pochta xabarlaringizni o‘qish uchun ruxsat beradi."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"brauzerdagi geolokatsiya ma’lumotlariga kirish huquqini o‘zgartirish"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Ilova brauzerdagi geolokatsiya ma’lumotlariga kirish sozlamalarini o‘zgartirishi mumkin. Zararli dasturlar uning yordamida joylashuv to‘g‘risidagi ma’lumotlarni boshqa istalgan veb-saytga yuborishi mumkin."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"paketlarni tekshirish"</string> @@ -1390,10 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ilova ishonchli agentlar xizmatiga ulanishi mumkin."</string> <string name="permlab_recovery" msgid="3157024487744125846">"Tizimni yangilash va tiklashni birgalikda amalga oshirish"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"Dasturga tizimni tiklash va yangilash imkoniyatlari bilan ishlash uchun ruxsat beradi."</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Kontentni translatsiya qilish seanslarini yaratish"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Ilovaga kontentni translatsiya qilish seanslarini yaratish uchun ruxsat beradi. Ushbu seanslar yordamida ilovalar qurilma ekranidagi tasvirlar va audio kontentda foydalanish huquqini qo‘lga kiritadi. Oddiy ilovalar uchun talab qilinmaydi."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Masshtabni o‘zgartirish uchun ikki marta bosing"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidjet qo‘shilmadi."</string> <string name="ime_action_go" msgid="8320845651737369027">"O‘tish"</string> @@ -1518,20 +1516,14 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Tahrirlash"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"Ma’lumotlardan foydalanish ogohlantirilishi"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"Trafik sarfi va sozlamalarni ko‘rish uchun bosing."</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G/3G internet o‘chirib qo‘yildi"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G internet o‘chirib qo‘yildi"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Mobil internet o‘chirib qo‘yildi"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi internet o‘chirib qo‘yildi"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"Chegaraga yetib keldi"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G ma’lumot cheklovdan o‘tdi"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G ma’lumot cheklovdan o‘tdi"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Mob. trafik cheg-dan oshib ketdi"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi ma’lumot cheklovdan o‘tdi"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Chegaradan <xliff:g id="SIZE">%s</xliff:g> oshib ketdi."</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"Orqa fon ma’lumotlari cheklangan"</string> @@ -1567,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Tizim"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Simsiz ekran"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Media chiqish"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Qurilmaga ulanish"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekrandagi tasvirni qurilmaga uzatish"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Qurilmalar izlanmoqda..."</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index b1c7acc51b62..c12ef19473e0 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Cho phép ứng dụng nhận và xử lý tin nhắn MAP qua Bluetooth. Điều này có nghĩa là ứng dụng có thể giám sát hoặc xóa tin nhắn được gửi đến thiết bị của bạn mà không hiển thị chúng cho bạn."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"truy xuất các ứng dụng đang chạy"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Cho phép ứng dụng truy xuất thông tin về các công việc đã và đang chạy gần đây. Việc này có thể cho phép ứng dụng phát hiện thông tin về những ứng dụng nào đã được sử dụng trên thiết bị."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"tương tác giữa người dùng"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Cho phép ứng dụng thực hiện hành động giữa những người dùng khác trên thiết bị. Ứng dụng độc hại có thể sử dụng quyền này để vi phạm khả năng bảo vệ giữa người dùng."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"cấp phép đầy đủ để tương tác giữa người dùng"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Hệ thống"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Hiển thị không dây"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Kết nối với thiết bị"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Truyền màn hình tới thiết bị"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Đang tìm kiếm thiết bị…"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index be51b8216fbd..d13d76cb8b8d 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -55,16 +55,16 @@ <string name="passwordIncorrect" msgid="7612208839450128715">"密码不正确。"</string> <string name="mmiComplete" msgid="8232527495411698359">"MMI 码已完成。"</string> <string name="badPin" msgid="9015277645546710014">"您输入的旧 PIN 不正确。"</string> - <string name="badPuk" msgid="5487257647081132201">"您输入的 PUK 码不正确。"</string> + <string name="badPuk" msgid="5487257647081132201">"您输入的PUK码不正确。"</string> <string name="mismatchPin" msgid="609379054496863419">"您输入的 PIN 码不一致。"</string> <string name="invalidPin" msgid="3850018445187475377">"输入一个 4 至 8 位数的 PIN 码。"</string> - <string name="invalidPuk" msgid="8761456210898036513">"请键入至少 8 位数字的 PUK 码。"</string> - <string name="needPuk" msgid="919668385956251611">"已对 SIM 卡进行 PUK 码锁定。键入 PUK 码将其解锁。"</string> - <string name="needPuk2" msgid="4526033371987193070">"输入 PUK2 码以解锁 SIM 卡。"</string> - <string name="enablePin" msgid="209412020907207950">"失败,请启用 SIM/RUIM 卡锁定设置。"</string> + <string name="invalidPuk" msgid="8761456210898036513">"请输入至少8位数字的PUK码。"</string> + <string name="needPuk" msgid="919668385956251611">"已对SIM卡进行PUK码锁定。键入PUK码将其解锁。"</string> + <string name="needPuk2" msgid="4526033371987193070">"输入PUK2码以解锁SIM卡。"</string> + <string name="enablePin" msgid="209412020907207950">"失败,请启用SIM/RUIM 卡锁定设置。"</string> <plurals name="pinpuk_attempts"> - <item quantity="one" msgid="6596245285809790142">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM 卡将被锁定。"</item> - <item quantity="other" msgid="7530597808358774740">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM 卡将被锁定。"</item> + <item quantity="one" msgid="6596245285809790142">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将被锁定。"</item> + <item quantity="other" msgid="7530597808358774740">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将被锁定。"</item> </plurals> <string name="imei" msgid="2625429890869005782">"IMEI"</string> <string name="meid" msgid="4841221237681254195">"MEID"</string> @@ -287,17 +287,21 @@ <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"发送“通过信息回复”事件"</string> <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"允许应用向其他信息应用发送请求,以便处理来电的“通过信息回复”事件。"</string> <string name="permlab_readSms" msgid="8745086572213270480">"读取您的讯息(短信或彩信)"</string> - <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"允许该应用读取您平板电脑或 SIM 卡上存储的短信。此权限可让该应用读取所有短信,而不考虑短信内容或机密性。"</string> - <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"允许该应用读取您手机或 SIM 卡上存储的短信。此权限可让该应用读取所有短信,而不考虑短信内容或机密性。"</string> + <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"允许该应用读取您平板电脑或SIM卡上存储的短信。此权限可让该应用读取所有短信,而不考虑短信内容或机密性。"</string> + <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"允许该应用读取您手机或SIM卡上存储的短信。此权限可让该应用读取所有短信,而不考虑短信内容或机密性。"</string> <string name="permlab_writeSms" msgid="3216950472636214774">"编辑您的讯息(短信或彩信)"</string> - <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"允许应用对平板电脑或 SIM 卡上存储的短信执行写入操作。恶意应用可能会删除您的短信。"</string> - <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"允许应用对手机或 SIM 卡上存储的短信执行写入操作。恶意应用可能会删除您的短信。"</string> + <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"允许应用对平板电脑或SIM卡上存储的短信执行写入操作。恶意应用可能会删除您的短信。"</string> + <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"允许应用对手机或SIM卡上存储的短信执行写入操作。恶意应用可能会删除您的短信。"</string> <string name="permlab_receiveWapPush" msgid="5991398711936590410">"接收讯息 (WAP)"</string> <string name="permdesc_receiveWapPush" msgid="748232190220583385">"允许该应用接收和处理 WAP 消息。此权限包括监视发送给您的消息或删除发送给您的消息而不向您显示的功能。"</string> <string name="permlab_receiveBluetoothMap" msgid="7593811487142360528">"接收蓝牙信息(MAP)"</string> <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"允许此应用接收和处理蓝牙MAP信息。这意味着,该应用可能会监视发送或到您设备的信息,在您阅读发送到您设备的信息之前擅自删除信息。"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"检索正在运行的应用"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"允许该应用检索近期运行的和当前正在运行的任务的相关信息。此权限可让该应用了解设备上使用了哪些应用。"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"用户间互动"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"允许该应用在设备上跨多个用户执行操作。恶意应用可能会借此破坏用户之间的保护措施。"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"完全允许在用户之间进行互动"</string> @@ -870,8 +874,8 @@ <string name="sipAddressTypeOther" msgid="4408436162950119849">"其他"</string> <string name="quick_contacts_not_available" msgid="746098007828579688">"找不到可用来查看此联系人的应用。"</string> <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入 PIN 码"</string> - <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"请输入 PUK 码和新的 PIN 码"</string> - <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK 码"</string> + <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"请输入PUK码和新的PIN码"</string> + <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK码"</string> <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"新的 PIN 码"</string> <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"触摸可输入密码"</font></string> <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"输入密码以解锁"</string> @@ -894,13 +898,13 @@ <string name="lockscreen_charged" msgid="321635745684060624">"充电完成"</string> <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> <string name="lockscreen_low_battery" msgid="1482873981919249740">"连接您的充电器。"</string> - <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有 SIM 卡"</string> - <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板电脑中没有 SIM 卡。"</string> - <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手机中无 SIM 卡"</string> - <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"请插入 SIM 卡"</string> - <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM 卡缺失或无法读取。请插入 SIM 卡。"</string> - <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM 卡无法使用。"</string> - <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"您的 SIM 卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张 SIM 卡。"</string> + <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有SIM卡"</string> + <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板电脑中没有SIM卡。"</string> + <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手机中无SIM卡"</string> + <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"请插入SIM卡"</string> + <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM卡缺失或无法读取。请插入SIM卡。"</string> + <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM卡无法使用。"</string> + <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"您的SIM卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张SIM卡。"</string> <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"“上一曲目”按钮"</string> <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"“下一曲目”按钮"</string> <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"“暂停”按钮"</string> @@ -908,10 +912,10 @@ <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"“停止”按钮"</string> <string name="emergency_calls_only" msgid="6733978304386365407">"只能拨打紧急呼救电话"</string> <string name="lockscreen_network_locked_message" msgid="143389224986028501">"网络已锁定"</string> - <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM 卡已用 PUK 码锁定"</string> + <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM卡已用PUK码锁定。"</string> <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"请参阅《用户指南》或与客服人员联系。"</string> - <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 卡被锁定"</string> - <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"正在解锁 SIM 卡..."</string> + <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM卡被锁定"</string> + <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"正在解锁SIM卡..."</string> <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string> <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了密码。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string> <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了 PIN。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string> @@ -1006,16 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"允许该应用修改您手机上存储的浏览器历史记录或浏览器书签。此权限可让该应用清除或修改浏览器数据。请注意:此权限可能不适用于第三方浏览器或具备网页浏览功能的其他应用。"</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"设置闹钟"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"允许应用在已安装的闹钟应用中设置闹钟。有些闹钟应用可能无法实现此功能。"</string> - <!-- no translation found for permlab_writeVoicemail (7309899891683938100) --> - <skip /> - <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) --> - <skip /> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"写入语音邮件"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"允许应用修改和移除您语音信箱中的语音邮件。"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"添加语音邮件"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允许应用向您的语音信箱收件箱添加邮件。"</string> - <!-- no translation found for permlab_readVoicemail (8415201752589140137) --> - <skip /> - <!-- no translation found for permdesc_readVoicemail (8926534735321616550) --> - <skip /> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"读取语音邮件"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"允许应用读取您的语音邮件。"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"修改“浏览器”地理位置的权限"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"允许应用修改“浏览器”的地理位置权限。恶意应用可能借此向任意网站发送位置信息。"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"验证软件包"</string> @@ -1291,10 +1291,10 @@ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"之后,您可以在“设置”>“应用”中更改此设置"</string> <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"始终允许"</string> <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"永不允许"</string> - <string name="sim_removed_title" msgid="6227712319223226185">"已移除 SIM 卡"</string> + <string name="sim_removed_title" msgid="6227712319223226185">"已移除SIM卡"</string> <string name="sim_removed_message" msgid="5450336489923274918">"您需要先插入有效的SIM卡再重新开机,然后才能使用移动网络。"</string> <string name="sim_done_button" msgid="827949989369963775">"完成"</string> - <string name="sim_added_title" msgid="3719670512889674693">"已添加 SIM 卡"</string> + <string name="sim_added_title" msgid="3719670512889674693">"已添加SIM卡"</string> <string name="sim_added_message" msgid="7797975656153714319">"请重新启动您的设备,以便使用移动网络。"</string> <string name="sim_restart_button" msgid="4722407842815232347">"重新启动"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"设置时间"</string> @@ -1329,7 +1329,7 @@ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"作为相机连接"</string> <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"作为安装程序连接"</string> <string name="usb_accessory_notification_title" msgid="7848236974087653666">"已连接到USB配件"</string> - <string name="usb_notification_message" msgid="2290859399983720271">"触摸可显示其他 USB 选项。"</string> + <string name="usb_notification_message" msgid="2290859399983720271">"触摸可显示其他USB选项。"</string> <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"格式化 USB 存储设备吗?"</string> <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"要格式化 SD 卡吗?"</string> <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"您的 USB 存储设备中存储的所有文件都将清除。该操作无法撤消!"</string> @@ -1390,10 +1390,8 @@ <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允许应用绑定至信任的代理服务。"</string> <string name="permlab_recovery" msgid="3157024487744125846">"与更新和恢复系统互动"</string> <string name="permdesc_recovery" msgid="8511774533266359571">"允许应用与恢复系统和系统更新互动。"</string> - <!-- no translation found for permlab_createMediaProjection (4941338725487978112) --> - <skip /> - <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) --> - <skip /> + <string name="permlab_createMediaProjection" msgid="4941338725487978112">"创建媒体投影会话"</string> + <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"允许应用创建媒体投影会话。这些会话可让应用截取显示内容和音频内容。普通应用绝不需要此权限。"</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"触摸两次可进行缩放控制"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"无法添加小部件。"</string> <string name="ime_action_go" msgid="8320845651737369027">"开始"</string> @@ -1518,20 +1516,14 @@ <string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"流量警告"</string> <string name="data_usage_warning_body" msgid="2814673551471969954">"触摸可查看使用情况和设置。"</string> - <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) --> - <skip /> - <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) --> - <skip /> - <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) --> - <skip /> - <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) --> - <skip /> - <!-- no translation found for data_usage_limit_body (6131350187562939365) --> - <skip /> + <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G数据网络已关闭"</string> + <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G数据网络已关闭"</string> + <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"移动数据网络已关闭"</string> + <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"WLAN数据网络已关闭"</string> + <string name="data_usage_limit_body" msgid="6131350187562939365">"已达到上限"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"已超出 2G-3G 数据流量限制"</string> <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"已超出 4G 数据使用上限"</string> - <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) --> - <skip /> + <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"已超出移动数据流量上限"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"超出了 WLAN 数据流量上限"</string> <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"超出规定上限 <xliff:g id="SIZE">%s</xliff:g>。"</string> <string name="data_usage_restricted_title" msgid="5965157361036321914">"后台流量受限制"</string> @@ -1553,7 +1545,7 @@ <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"查看全部"</string> <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"选择活动"</string> <string name="share_action_provider_share_with" msgid="5247684435979149216">"分享方式"</string> - <string name="list_delimeter" msgid="3975117572185494152">"、 "</string> + <string name="list_delimeter" msgid="3975117572185494152">", "</string> <string name="sending" msgid="3245653681008218030">"正在发送..."</string> <string name="launchBrowserDefault" msgid="2057951947297614725">"要启动浏览器吗?"</string> <string name="SetupCallDefault" msgid="5834948469253758575">"要接听电话吗?"</string> @@ -1567,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"系统"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"无线显示"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"连接到设备"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"将屏幕投射到设备上"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜索设备…"</string> @@ -1595,17 +1588,17 @@ <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 有误"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%1$d</xliff:g> 秒后重试。"</string> <string name="kg_pattern_instructions" msgid="398978611683075868">"绘制您的图案"</string> - <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入 SIM PIN"</string> + <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入SIM卡PIN码"</string> <string name="kg_pin_instructions" msgid="2377242233495111557">"输入 PIN"</string> <string name="kg_password_instructions" msgid="5753646556186936819">"输入密码"</string> - <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡已被停用,需要输入 PUK 码才能继续使用。有关详情,请联系您的运营商。"</string> + <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM卡已被停用,需要输入PUK码才能继续使用。有关详情,请联系您的运营商。"</string> <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"请输入所需 PIN 码"</string> <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"请确认所需 PIN 码"</string> - <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁 SIM 卡..."</string> + <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁SIM卡..."</string> <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 码有误。"</string> <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入 4 至 8 位数的 PIN。"</string> <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK码应包含8位数字。"</string> - <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的 PUK 码。如果尝试错误次数过多,SIM 卡将永久停用。"</string> + <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的PUK码。如果尝试错误次数过多,SIM卡将永久停用。"</string> <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 码不匹配"</string> <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string> <string name="kg_login_instructions" msgid="1100551261265506448">"要解锁,请登录您的 Google 帐户。"</string> @@ -1758,9 +1751,9 @@ <string name="lock_to_app_description" msgid="2800403592608529611">"“单应用模式”功能会锁定屏幕,使其只显示一个应用。{\n\n要退出,请触摸并按住“最近用过的应用”按钮。"</string> <string name="lock_to_app_negative" msgid="2259143719362732728">"不用了"</string> <string name="lock_to_app_positive" msgid="7085139175671313864">"启动"</string> - <string name="lock_to_app_start" msgid="3074665051586318340">"开启单应用模式"</string> - <string name="lock_to_app_exit" msgid="8967089657201849300">"不再使用单应用模式"</string> - <string name="lock_to_app_use_screen_lock" msgid="1434584309048590886">"退出前要求%1$s"</string> + <string name="lock_to_app_start" msgid="3074665051586318340">"已开启单应用模式"</string> + <string name="lock_to_app_exit" msgid="8967089657201849300">"已退出单应用模式"</string> + <string name="lock_to_app_use_screen_lock" msgid="1434584309048590886">"退出前要求输入%1$s"</string> <string name="lock_to_app_unlock_pin" msgid="7908385370846820001">"PIN码"</string> <string name="lock_to_app_unlock_pattern" msgid="7763071104790758405">"解锁图案"</string> <string name="lock_to_app_unlock_password" msgid="795224196583495868">"密码"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 8f7b5a08acca..366ff2492093 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"允許應用程式接收和處理藍牙 MAP 訊息。這項設定可讓應用程式監控傳送至您裝置的訊息,或在您閱讀訊息前擅自刪除訊息。"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"擷取執行中的應用程式"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"允許應用程式擷取有關目前和最近執行的工作的資訊。如此一來,應用程式或可找出裝置上所使用應用程式的相關資訊。"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"與其他用戶互動"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"允許應用程式對裝置上的不同用戶執行各種操作。請注意,惡意應用程式可能藉此破壞各用戶之間的保護機制。"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"全面授權與其他用戶互動"</string> @@ -1006,12 +1010,12 @@ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"允許應用程式修改手機上儲存的瀏覽器記錄或書籤。如此一來,應用程式或可清除或修改瀏覽器資料。注意:這項權限可能不適用於第三方瀏覽器或其他具備網頁瀏覽功能的應用程式。"</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"設定鬧鐘"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"允許應用程式在安裝的鬧鐘應用程式中設定鬧鐘,某些鬧鐘應用程式可能沒有這項功能。"</string> - <string name="permlab_writeVoicemail" msgid="7309899891683938100">"寫入語音留言"</string> - <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"允許應用程式修改及移除語音留言收件匣中的訊息。"</string> + <string name="permlab_writeVoicemail" msgid="7309899891683938100">"寫入留言訊息"</string> + <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"允許應用程式修改和移除留言信箱中的訊息。"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"新增留言"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允許應用程式將訊息加到您的留言信箱收件箱。"</string> - <string name="permlab_readVoicemail" msgid="8415201752589140137">"讀取語音留言"</string> - <string name="permdesc_readVoicemail" msgid="8926534735321616550">"允許應用程式讀取您的語音留言。"</string> + <string name="permlab_readVoicemail" msgid="8415201752589140137">"讀取留言訊息"</string> + <string name="permdesc_readVoicemail" msgid="8926534735321616550">"允許應用程式讀取您的留言訊息。"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"修改瀏覽器地理資訊的權限"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"允許應用程式修改瀏覽器的地理資訊權限。惡意應用程式可能會藉此允許將您的位置資訊任意傳送給某些網站。"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"驗證套件"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音頻"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"連接裝置"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"在裝置上放送螢幕"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜尋裝置…"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index fbffc99b05e0..32d61148f364 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"允許應用程式接收及處理藍牙 MAP 訊息。這項設定可讓應用程式監控傳送至您裝置的訊息,或在您閱讀訊息前主動刪除訊息。"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"擷取執行中的應用程式"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"允許應用程式擷取最近執行工作的資訊。這項設定可讓應用程式找出裝置所用程式的相關資訊。"</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"對所有使用者執行各種動作"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"允許應用程式對裝置上的所有使用者執行各種動作。請注意,惡意應用程式可能利用此功能侵害使用者之間的保護機制。"</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"完整授權對所有使用者執行各種動作"</string> @@ -1181,11 +1185,11 @@ <string name="whichApplication" msgid="4533185947064773386">"選擇要使用的應用程式"</string> <string name="whichApplicationNamed" msgid="8260158865936942783">"完成操作需使用 %1$s"</string> <string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟工具"</string> - <string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用 %1$s 開啟"</string> + <string name="whichViewApplicationNamed" msgid="2286418824011249620">"透過 %1$s 開啟"</string> <string name="whichEditApplication" msgid="144727838241402655">"選擇編輯工具"</string> <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string> - <string name="whichSendApplication" msgid="6902512414057341668">"選擇分享對象"</string> - <string name="whichSendApplicationNamed" msgid="2799370240005424391">"與 %1$s 共用"</string> + <string name="whichSendApplication" msgid="6902512414057341668">"選擇分享工具"</string> + <string name="whichSendApplicationNamed" msgid="2799370240005424391">"透過 %1$s 分享"</string> <string name="whichHomeApplication" msgid="4616420172727326782">"選取主螢幕應用程式"</string> <string name="alwaysUse" msgid="4583018368000610438">"設為預設應用程式。"</string> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"前往 [系統設定] > [應用程式] > [下載] 清除預設值。"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"連線至裝置"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"將螢幕投放到裝置上"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜尋裝置..."</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 7f4e78b3c6f4..bd3cc3f4642f 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -298,6 +298,10 @@ <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Ivumela uhlelo lokusebenza ukuthola nokucubungula imilayezo ye-Bluetooth MAP. Lokhu kusho ukuthi uhlelo lokusebenza lingakwazi ukugada noma ukususa imilayezo ethunyelwa kwidivayisi yakho ngaphandle kokukubonisa yona."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"thola izinhlelo zokusebenza ezisebenzayo"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Ivumela uhlelo lokusebenza ukubuyisa ulwazi mayelana nemisebenzi yamanje neyakamuva. Lokhu kungavumela uhlelo lokusebenza ukuthola ulwazi mayelana nokuthi iziphi izinhlelo zokusebenza ezisetshenziswa kudivayisi."</string> + <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) --> + <skip /> + <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) --> + <skip /> <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ihlanganyela phakathi kwabasebenzisi"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ivumela uhlelo lokusebenza ukwenza izenzo kubasebenzisi bonke kudivayisi. Izinhlelo zokusebenza ezingalungile zingasebenzisa lokhu ukwephula ukuvikela phakathi kwabasebenzisi."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ilayisensi egcwele yokuhlanganyela kubasebenzisi"</string> @@ -1555,7 +1559,8 @@ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Isistimu"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string> <string name="wireless_display_route_description" msgid="9070346425023979651">"Ukubonisa okungenazintambo"</string> - <string name="media_route_button_content_description" msgid="5758553567065145276">"Okukhiphayo kwemidiya"</string> + <!-- no translation found for media_route_button_content_description (591703006349356016) --> + <skip /> <string name="media_route_chooser_title" msgid="1751618554539087622">"Xhuma kudivayisi"</string> <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Lingisa isikrini kudivayisi"</string> <string name="media_route_chooser_searching" msgid="4776236202610828706">"Isesha amadivayisi…"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 2782b523a33b..19d58c74589c 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1847,6 +1847,9 @@ <!-- Elevation to use for the window. --> <attr name="windowElevation" format="dimension" /> + + <!-- Whether to clip window content to the outline of the window background. --> + <attr name="windowClipToOutline" format="boolean" /> </declare-styleable> <!-- The set of attributes that describe a AlertDialog's theme. --> @@ -3755,6 +3758,8 @@ <attr name="shadowRadius" format="float" /> <!-- Elegant text height, especially for less compacted complex script text. --> <attr name="elegantTextHeight" format="boolean" /> + <!-- Text letter-spacing. --> + <attr name="letterSpacing" format="float" /> </declare-styleable> <declare-styleable name="TextClock"> <!-- Specifies the formatting pattern used to show the time and/or date @@ -4048,6 +4053,8 @@ <attr name="textAllCaps" /> <!-- Elegant text height, especially for less compacted complex script text. --> <attr name="elegantTextHeight" /> + <!-- Text letter-spacing. --> + <attr name="letterSpacing" /> </declare-styleable> <declare-styleable name="TextViewAppearance"> <!-- Base text color, typeface, size, and style. --> @@ -5112,24 +5119,16 @@ <!-- Indicates if the drawable needs to be mirrored when its layout direction is RTL (right-to-left). --> <attr name="autoMirrored" /> - </declare-styleable> - - <!-- Define the virtual size of the drawing surface paths will draw to. --> - <declare-styleable name="VectorDrawableViewport"> + <!-- The intrinsic width of the Vector Drawable. --> + <attr name="width" /> + <!-- The intrinsic height of the Vector Drawable. --> + <attr name="height" /> <!-- The width of the canvas the drawing is on. --> <attr name="viewportWidth" format="float"/> <!-- The height of the canvas the drawing is on. --> <attr name="viewportHeight" format="float"/> </declare-styleable> - <!-- Define the size of the drawable --> - <declare-styleable name="VectorDrawableSize"> - <!-- Width of the Vector Drawable. --> - <attr name="width" /> - <!-- Height of the Vector Drawable. --> - <attr name="height" /> - </declare-styleable> - <!-- Defines the group used in VectorDrawables. --> <declare-styleable name="VectorDrawableGroup"> <!-- The Name of this group --> @@ -5161,9 +5160,9 @@ <!-- The opacity of a path stroke --> <attr name="strokeOpacity" format="float" /> <!-- The color to stroke the path if not defined implies no stroke--> - <attr name="stroke" format="color" /> + <attr name="strokeColor" format="color" /> <!-- The color to fill the path if not defined implies no fill--> - <attr name="fill" format="color" /> + <attr name="fillColor" format="color" /> <!-- The level of opacity of the filled area of the path --> <attr name="fillOpacity" format="float" /> <!-- The specification of the operations that define the path --> @@ -5174,7 +5173,7 @@ <attr name="trimPathEnd" format="float" /> <!-- Shift trim region (allows visible region to include the start and end) from 0 to 1 --> <attr name="trimPathOffset" format="float" /> - <!-- Path will set the current clip path --> + <!-- TODO: Remove this. Path will set the current clip path --> <attr name="clipToPath" format="boolean" /> <!-- sets the linecap for a stroked path --> <attr name="strokeLineCap" format="enum"> @@ -5192,6 +5191,14 @@ <attr name="strokeMiterLimit" format="float"/> </declare-styleable> + <!-- Defines the clip path used in VectorDrawables. --> + <declare-styleable name="VectorDrawableClipPath"> + <!-- The Name of this path --> + <attr name="name" /> + <!-- The specification of the operations that define the path --> + <attr name="pathData"/> + </declare-styleable> + <!-- ========================== --> <!-- AnimatedVectorDrawable class --> <!-- ========================== --> @@ -5451,14 +5458,14 @@ described here. --> <declare-styleable name="Slide"> <attr name="slideEdge"> + <!-- Slide to and from the left edge of the Scene. --> + <enum name="left" value="0x03" /> + <!-- Slide to and from the top edge of the Scene. --> + <enum name="top" value="0x30" /> + <!-- Slide to and from the right edge of the Scene. --> + <enum name="right" value="0x05" /> <!-- Slide to and from the bottom edge of the Scene. --> - <enum name="left" value="0" /> - <!-- Slide to and from the bottom edge of the Scene. --> - <enum name="top" value="1" /> - <!-- Slide to and from the bottom edge of the Scene. --> - <enum name="right" value="2" /> - <!-- Slide to and from the bottom edge of the Scene. --> - <enum name="bottom" value="3" /> + <enum name="bottom" value="0x50" /> </attr> </declare-styleable> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 7311a60d531f..c268d974c718 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1285,6 +1285,19 @@ <attr name="required" format="boolean" /> </declare-styleable> + <!-- The <code>feature-group</code> tag specifies + a set of one or more <code>uses-feature</code> elements that + the application can utilize. An application uses multiple + <code>feature-group</code> sets to indicate that it can support + different combinations of features. + + <p>This appears as a child tag of the root + {@link #AndroidManifest manifest} tag. --> + <declare-styleable name="AndroidManifestFeatureGroup"> + <!-- The human-readable name of the feature group. --> + <attr name="label" /> + </declare-styleable> + <!-- The <code>uses-sdk</code> tag describes the SDK features that the containing package must be running on to operate correctly. diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 0954ddf99f50..7f160e83d154 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1588,6 +1588,9 @@ <!-- default device has recents property --> <bool name="config_hasRecents">true</bool> + <!-- default window ShowCircularMask property --> + <bool name="config_windowShowCircularMask">false</bool> + <!-- Defines the default set of global actions. Actions may still be disabled or hidden based on the current state of the device. Each item must be one of the following strings: diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 77b115b53267..afe180f54c55 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -384,4 +384,9 @@ <dimen name="immersive_mode_cling_width">-1px</dimen> <dimen name="resolver_max_width">480dp</dimen> + + <!-- Size of the offset applied to the position of the circular mask. This is only + used on circular displays. In the case where there is no "chin", this will default + to 0 --> + <dimen name="circular_display_mask_offset">0px</dimen> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index a6e85e934ff8..0a87d0d41b88 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2119,9 +2119,9 @@ <public type="attr" name="viewportWidth" /> <public type="attr" name="viewportHeight" /> <public type="attr" name="fillOpacity" /> - <public type="attr" name="fill" /> + <public type="attr" name="fillColor" /> <public type="attr" name="pathData" /> - <public type="attr" name="stroke" /> + <public type="attr" name="strokeColor" /> <public type="attr" name="strokeOpacity" /> <public type="attr" name="strokeWidth" /> <public type="attr" name="trimPathStart" /> @@ -2268,6 +2268,7 @@ <public type="attr" name="checkMarkTintMode" /> <public type="attr" name="popupTheme" /> <public type="attr" name="toolbarStyle" /> + <public type="attr" name="windowClipToOutline" /> <public-padding type="dimen" name="l_resource_pad" end="0x01050010" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 351acf0a8f11..c6ee89fedb64 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3872,6 +3872,11 @@ <!-- Description of an application permission that lets it create media projection sessions. --> <string name="permdesc_createMediaProjection">Allows an application to create media projection sessions. These sessions can provide applications the ability to capture display and audio contents. Should never be needed by normal apps.</string> + <!-- Title of an application permission that lets it read install sessions. --> + <string name="permlab_readInstallSessions">Read install sessions</string> + <!-- Description of an application permission that lets it read install sessions. --> + <string name="permdesc_readInstallSessions">Allows an application to read install sessions. This allows it to see details about active package installations.</string> + <!-- Shown in the tutorial for tap twice for zoom control. --> <string name="tutorial_double_tap_to_zoom_message_short">Touch twice for zoom control</string> @@ -4493,7 +4498,7 @@ <!-- Message shown in dialog when user is attempting to set the music volume above the recommended maximum level for headphones --> <string name="safe_media_volume_warning" product="default"> - "Raise volume above recommended level?\nListening at high volume for long periods may damage your hearing." + "Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing." </string> <!-- Text spoken when the user is performing a gesture that will enable accessibility. [CHAR LIMIT=none] --> @@ -4508,8 +4513,8 @@ <string name="owner_name" msgid="3879126011135546571">Owner</string> <!-- Error message title [CHAR LIMIT=35] --> <string name="error_message_title">Error</string> - <!-- Message informing user that app is not permitted to access accounts. [CHAR LIMIT=none] --> - <string name="app_no_restricted_accounts">This app doesn\'t support accounts for restricted profiles</string> + <!-- Message informing user that the change was disallowed by an administrator. [CHAR LIMIT=none] --> + <string name="error_message_change_not_allowed">This change isn\'t allowed by your administrator</string> <!-- Message informing user that the requested activity could not be found [CHAR LIMIT=none] --> <string name="app_not_found">No application found to handle this action</string> <string name="revoke">Revoke</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9f627b4dea75..30209e92da41 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -289,6 +289,7 @@ <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/> <java-symbol type="bool" name="config_windowIsRound" /> <java-symbol type="bool" name="config_hasRecents" /> + <java-symbol type="bool" name="config_windowShowCircularMask" /> <java-symbol type="integer" name="config_bluetooth_max_advertisers" /> <java-symbol type="integer" name="config_bluetooth_max_scan_filters" /> @@ -349,6 +350,7 @@ <java-symbol type="dimen" name="notification_title_text_size" /> <java-symbol type="dimen" name="notification_subtext_size" /> <java-symbol type="dimen" name="immersive_mode_cling_width" /> + <java-symbol type="dimen" name="circular_display_mask_offset" /> <java-symbol type="string" name="add_account_button_label" /> <java-symbol type="string" name="addToDictionary" /> @@ -875,7 +877,7 @@ <java-symbol type="string" name="config_customResolverActivity" /> <java-symbol type="string" name="config_appsAuthorizedForSharedAccounts" /> <java-symbol type="string" name="error_message_title" /> - <java-symbol type="string" name="app_no_restricted_accounts" /> + <java-symbol type="string" name="error_message_change_not_allowed" /> <java-symbol type="string" name="action_bar_home_description_format" /> <java-symbol type="string" name="action_bar_home_subtitle_description_format" /> <java-symbol type="string" name="wireless_display_route_description" /> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 0d4a2bf79e4d..aea72c1db960 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -169,6 +169,7 @@ please see themes_device_defaults.xml. <!-- Window attributes --> <item name="windowBackground">@drawable/screen_background_selector_dark</item> + <item name="windowClipToOutline">false</item> <item name="windowFrame">@null</item> <item name="windowNoTitle">false</item> <item name="windowFullscreen">false</item> @@ -473,6 +474,8 @@ please see themes_device_defaults.xml. <p>This is designed for API level 10 and lower.</p>--> <style name="Theme.Light"> <item name="windowBackground">@drawable/screen_background_selector_light</item> + <item name="windowClipToOutline">false</item> + <item name="colorBackground">@color/background_light</item> <item name="colorForeground">@color/bright_foreground_light</item> <item name="colorForegroundInverse">@color/bright_foreground_light_inverse</item> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 741ffe6766ae..f2233e08095f 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -146,6 +146,7 @@ please see themes_device_defaults.xml. <!-- Window attributes --> <item name="windowBackground">@color/background_material_dark</item> + <item name="windowClipToOutline">true</item> <item name="windowFrame">@null</item> <item name="windowNoTitle">false</item> <item name="windowFullscreen">false</item> @@ -512,6 +513,7 @@ please see themes_device_defaults.xml. <!-- Window attributes --> <item name="windowBackground">@color/background_material_light</item> + <item name="windowClipToOutline">true</item> <item name="windowFrame">@null</item> <item name="windowNoTitle">false</item> <item name="windowFullscreen">false</item> diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java index e259bcc9add9..ccdd90ae457b 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java @@ -27,8 +27,7 @@ import java.util.Arrays; /** * Unit test cases for {@link ScanRecord}. * <p> - * To run this test, use adb shell am instrument -e class - * 'android.bluetooth.ScanRecordTest' -w + * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanRecordTest' -w * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner' */ public class ScanRecordTest extends TestCase { @@ -54,13 +53,13 @@ public class ScanRecordTest extends TestCase { assertEquals("Ped", data.getDeviceName()); assertEquals(-20, data.getTxPowerLevel()); - assertEquals(224, data.getManufacturerId()); + assertEquals(0x00e0, data.getManufacturerId()); assertArrayEquals(new byte[] { - (byte) 0xe0, 0x00, 0x02, 0x15 }, data.getManufacturerSpecificData()); + 0x02, 0x15 }, data.getManufacturerSpecificData()); assertEquals(uuid2, data.getServiceDataUuid()); assertArrayEquals(new byte[] { - 0x0b, 0x11, 0x50, 0x64 }, data.getServiceData()); + 0x50, 0x64 }, data.getServiceData()); } // Assert two byte arrays are equal. diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java new file mode 100644 index 000000000000..7c42c3b46775 --- /dev/null +++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java @@ -0,0 +1,64 @@ +/* + * 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 android.bluetooth.le; + +import android.test.suitebuilder.annotation.SmallTest; + +import junit.framework.TestCase; + +/** + * Test for Bluetooth LE {@link ScanSettings}. + */ +public class ScanSettingsTest extends TestCase { + + @SmallTest + public void testCallbackType() { + ScanSettings.Builder builder = new ScanSettings.Builder(); + builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES); + builder.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH); + builder.setCallbackType(ScanSettings.CALLBACK_TYPE_MATCH_LOST); + builder.setCallbackType( + ScanSettings.CALLBACK_TYPE_FIRST_MATCH | ScanSettings.CALLBACK_TYPE_MATCH_LOST); + try { + builder.setCallbackType( + ScanSettings.CALLBACK_TYPE_ALL_MATCHES | ScanSettings.CALLBACK_TYPE_MATCH_LOST); + fail("should have thrown IllegalArgumentException!"); + } catch (IllegalArgumentException e) { + // nothing to do + } + + try { + builder.setCallbackType( + ScanSettings.CALLBACK_TYPE_ALL_MATCHES | + ScanSettings.CALLBACK_TYPE_FIRST_MATCH); + fail("should have thrown IllegalArgumentException!"); + } catch (IllegalArgumentException e) { + // nothing to do + } + + try { + builder.setCallbackType( + ScanSettings.CALLBACK_TYPE_ALL_MATCHES | + ScanSettings.CALLBACK_TYPE_FIRST_MATCH | + ScanSettings.CALLBACK_TYPE_MATCH_LOST); + fail("should have thrown IllegalArgumentException!"); + } catch (IllegalArgumentException e) { + // nothing to do + } + + } +} diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java index ca68e939e635..3a598f266681 100644 --- a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java +++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java @@ -295,4 +295,33 @@ public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTe assertRotationOrder(anotherController, false /* onlyCurrentIme */, switchingUnawarelatinIme_en_UK, switchUnawareJapaneseIme_ja_JP); } + + @SmallTest + public void testImeSubtypeListItem() throws Exception { + final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>(); + addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", + Arrays.asList("en_US", "fr", "en", "en_uk", "enn", "e", "EN_US"), + true /* supportsSwitchingToNextInputMethod*/); + final ImeSubtypeListItem item_en_US = items.get(0); + final ImeSubtypeListItem item_fr = items.get(1); + final ImeSubtypeListItem item_en = items.get(2); + final ImeSubtypeListItem item_enn = items.get(3); + final ImeSubtypeListItem item_e = items.get(4); + final ImeSubtypeListItem item_EN_US = items.get(5); + + assertTrue(item_en_US.mIsSystemLocale); + assertFalse(item_fr.mIsSystemLocale); + assertFalse(item_en.mIsSystemLocale); + assertFalse(item_en.mIsSystemLocale); + assertFalse(item_enn.mIsSystemLocale); + assertFalse(item_e.mIsSystemLocale); + assertFalse(item_EN_US.mIsSystemLocale); + + assertTrue(item_en_US.mIsSystemLanguage); + assertFalse(item_fr.mIsSystemLanguage); + assertTrue(item_en.mIsSystemLanguage); + assertFalse(item_enn.mIsSystemLocale); + assertFalse(item_e.mIsSystemLocale); + assertFalse(item_EN_US.mIsSystemLocale); + } } diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk index 9f6b64cb921f..80fb1fdd3a8a 100644 --- a/data/fonts/Android.mk +++ b/data/fonts/Android.mk @@ -47,14 +47,8 @@ extra_font_files := \ DroidSans-Bold.ttf ################################ -# On space-constrained devices, we include a subset of fonts: -ifeq ($(SMALLER_FONT_FOOTPRINT),true) - -droidsans_fallback_src := DroidSansFallback.ttf - -else # !SMALLER_FONT_FOOTPRINT - -droidsans_fallback_src := DroidSansFallbackFull.ttf +# Do not include Motoya on space-constrained devices +ifneq ($(SMALLER_FONT_FOOTPRINT),true) include $(CLEAR_VARS) LOCAL_MODULE := MTLmr3m.ttf @@ -65,24 +59,44 @@ LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts include $(BUILD_PREBUILT) extra_font_files += MTLmr3m.ttf -endif # SMALLER_FONT_FOOTPRINT +endif # !SMALLER_FONT_FOOTPRINT ################################ +# Use DroidSansMono to hang extra_font_files on include $(CLEAR_VARS) -LOCAL_MODULE := DroidSansFallback.ttf -LOCAL_SRC_FILES := $(droidsans_fallback_src) +LOCAL_MODULE := DroidSansMono.ttf +LOCAL_SRC_FILES := $(LOCAL_MODULE) LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts LOCAL_REQUIRED_MODULES := $(extra_font_files) include $(BUILD_PREBUILT) +extra_font_files := + +################################ +# Include DroidSansFallback only on non-EXTENDED_FONT_FOOTPRINT builds +ifneq ($(EXTENDED_FONT_FOOTPRINT),true) + +# Include a subset of DroidSansFallback on SMALLER_FONT_FOOTPRINT build +ifeq ($(SMALLER_FONT_FOOTPRINT),true) +droidsans_fallback_src := DroidSansFallback.ttf +else # !SMALLER_FONT_FOOTPRINT +droidsans_fallback_src := DroidSansFallbackFull.ttf +endif # SMALLER_FONT_FOOTPRINT -font_symlink_src := -font_symlink := +include $(CLEAR_VARS) +LOCAL_MODULE := DroidSansFallback.ttf +LOCAL_SRC_FILES := $(droidsans_fallback_src) +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts +include $(BUILD_PREBUILT) droidsans_fallback_src := -extra_font_files := + +endif # !EXTENDED_FONT_FOOTPRINT + ################################ -# Build the rest font files as prebuilt. +# Build the rest of font files as prebuilt. # $(1): The source file name in LOCAL_PATH. # It also serves as the module name and the dest file name. @@ -101,7 +115,6 @@ font_src_files := \ Roboto-Bold.ttf \ Roboto-Italic.ttf \ Roboto-BoldItalic.ttf \ - DroidSansMono.ttf \ Clockopia.ttf \ AndroidClock.ttf \ AndroidClock_Highlight.ttf \ diff --git a/data/fonts/DroidKufi-Bold.ttf b/data/fonts/DroidKufi-Bold.ttf Binary files differdeleted file mode 100644 index 650919e2601d..000000000000 --- a/data/fonts/DroidKufi-Bold.ttf +++ /dev/null diff --git a/data/fonts/DroidKufi-Regular.ttf b/data/fonts/DroidKufi-Regular.ttf Binary files differdeleted file mode 100644 index af859750b699..000000000000 --- a/data/fonts/DroidKufi-Regular.ttf +++ /dev/null diff --git a/data/fonts/DroidSans-Bold.ttf b/data/fonts/DroidSans-Bold.ttf Binary files differdeleted file mode 100644 index d065b64eb186..000000000000 --- a/data/fonts/DroidSans-Bold.ttf +++ /dev/null diff --git a/data/fonts/DroidSans.ttf b/data/fonts/DroidSans.ttf Binary files differdeleted file mode 100644 index ad1efca88aed..000000000000 --- a/data/fonts/DroidSans.ttf +++ /dev/null diff --git a/data/fonts/DroidSansFallbackFull.ttf b/data/fonts/DroidSansFallbackFull.ttf Binary files differindex 135723c68293..1dfcc330ebf8 100644 --- a/data/fonts/DroidSansFallbackFull.ttf +++ b/data/fonts/DroidSansFallbackFull.ttf diff --git a/data/fonts/DroidSansJapanese.ttf b/data/fonts/DroidSansJapanese.ttf Binary files differdeleted file mode 100644 index 412fa3de05e8..000000000000 --- a/data/fonts/DroidSansJapanese.ttf +++ /dev/null diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd index e86d4c9e21cd..1ee66062c4d2 100644 --- a/docs/html/guide/topics/resources/localization.jd +++ b/docs/html/guide/topics/resources/localization.jd @@ -402,8 +402,7 @@ that Android makes available:</p> resolution and density of the device screen may differ, which could affect
the display of strings and drawables in your UI.</p>
-<p>To change the locale on a device, use the Settings application (Home >
-Menu > Settings > Locale & text > Select locale). </p>
+<p>To change the locale or language on a device, use the Settings application.</p>
<h3 id="emulator">Testing on an Emulator</h3>
diff --git a/docs/html/preview/material/ui-widgets.jd b/docs/html/preview/material/ui-widgets.jd index 2d29420d727b..69b7d2d90886 100644 --- a/docs/html/preview/material/ui-widgets.jd +++ b/docs/html/preview/material/ui-widgets.jd @@ -132,7 +132,7 @@ public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { int viewType) { // create a new view View v = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.my_text_view, parent); + .inflate(R.layout.my_text_view, parent, false); // set the view's size, margins, paddings and layout parameters ... ViewHolder vh = new ViewHolder(v); diff --git a/graphics/java/android/graphics/BlurMaskFilter.java b/graphics/java/android/graphics/BlurMaskFilter.java index 939af5248f99..f3064f872041 100644 --- a/graphics/java/android/graphics/BlurMaskFilter.java +++ b/graphics/java/android/graphics/BlurMaskFilter.java @@ -25,10 +25,25 @@ package android.graphics; public class BlurMaskFilter extends MaskFilter { public enum Blur { - NORMAL(0), //!< blur inside and outside of the original border - SOLID(1), //!< include the original mask, blur outside - OUTER(2), //!< just blur outside the original border - INNER(3); //!< just blur inside the original border + /** + * Blur inside and outside the original border. + */ + NORMAL(0), + + /** + * Draw solid inside the border, blur outside. + */ + SOLID(1), + + /** + * Draw nothing inside the border, blur outside. + */ + OUTER(2), + + /** + * Blur inside the border, draw nothing outside. + */ + INNER(3); Blur(int value) { native_int = value; diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index ef4b26057c44..f3af8f6150e3 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -52,6 +52,9 @@ public class Canvas { return mNativeCanvasWrapper; } + /** @hide */ + public boolean isRecordingFor(Object o) { return false; } + // may be null private Bitmap mBitmap; diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index ab4258dfe46d..3efb9c0bf67d 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -236,17 +236,17 @@ public class ImageFormat { * Android 10-bit raw format * </p> * <p> - * This is a single-plane, 10-bit per pixel, densely packed, unprocessed - * format, usually representing raw Bayer-pattern images coming from an image - * sensor. + * This is a single-plane, 10-bit per pixel, densely packed (in each row), + * unprocessed format, usually representing raw Bayer-pattern images coming + * from an image sensor. * </p> * <p> - * In an image buffer with this format, starting from the first pixel, each - * 4 consecutive pixels are packed into 5 bytes (40 bits). Each one of the - * first 4 bytes contains the top 8 bits of each pixel, The fifth byte - * contains the 2 least significant bits of the 4 pixels, the exact layout - * data for each 4 consecutive pixels is illustrated below (Pi[j] stands for - * the jth bit of the ith pixel): + * In an image buffer with this format, starting from the first pixel of + * each row, each 4 consecutive pixels are packed into 5 bytes (40 bits). + * Each one of the first 4 bytes contains the top 8 bits of each pixel, The + * fifth byte contains the 2 least significant bits of the 4 pixels, the + * exact layout data for each 4 consecutive pixels is illustrated below + * ({@code Pi[j]} stands for the jth bit of the ith pixel): * </p> * <table> * <thead> @@ -327,23 +327,26 @@ public class ImageFormat { * </ul> * </p> * - * <pre> - * size = width * height * 10 / 8 - * </pre> + * <pre>size = row stride * height</pre> where the row stride is in <em>bytes</em>, + * not pixels. + * * <p> - * Since this is a densely packed format, the pixel and row stride are always - * 0. The application must use the pixel data layout defined in above table - * to access data. + * Since this is a densely packed format, the pixel stride is always 0. The + * application must use the pixel data layout defined in above table to + * access each row data. When row stride is equal to {@code width * (10 / 8)}, there + * will be no padding bytes at the end of each row, the entire image data is + * densely packed. When stride is larger than {@code width * (10 / 8)}, padding + * bytes will be present at the end of each row. * </p> - * * <p> * For example, the {@link android.media.Image} object can provide data in - * this format from a {@link android.hardware.camera2.CameraDevice} (if supported) - * through a {@link android.media.ImageReader} object. The + * this format from a {@link android.hardware.camera2.CameraDevice} (if + * supported) through a {@link android.media.ImageReader} object. The * {@link android.media.Image#getPlanes() Image#getPlanes()} will return a - * single plane containing the pixel data. The pixel stride and row stride - * are always 0 in {@link android.media.Image.Plane#getPixelStride()} and - * {@link android.media.Image.Plane#getRowStride()} respectively. + * single plane containing the pixel data. The pixel stride is always 0 in + * {@link android.media.Image.Plane#getPixelStride()}, and the + * {@link android.media.Image.Plane#getRowStride()} describes the vertical + * neighboring pixel distance (in bytes) between adjacent rows. * </p> * * @see android.media.Image diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 3f73a03ac68d..58a1bf24c62e 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1260,6 +1260,29 @@ public class Paint { public native void setTextSkewX(float skewX); /** + * Return the paint's letter-spacing for text. The default value + * is 0. + * + * @return the paint's letter-spacing for drawing text. + * @hide + */ + public float getLetterSpacing() { + return native_getLetterSpacing(mNativePaint); + } + + /** + * Set the paint's letter-spacing for text. The default value + * is 0. The value is in 'EM' units. Typical values for slight + * expansion will be around 0.05. Negative values tighten text. + * + * @param letterSpacing set the paint's letter-spacing for drawing text. + * @hide + */ + public void setLetterSpacing(float letterSpacing) { + native_setLetterSpacing(mNativePaint, letterSpacing); + } + + /** * Return the distance above (negative) the baseline (ascent) based on the * current typeface and text size. * @@ -2232,4 +2255,8 @@ public class Paint { private static native void native_setShadowLayer(long native_object, float radius, float dx, float dy, int color); private static native boolean native_hasShadowLayer(long native_object); + + private static native float native_getLetterSpacing(long native_object); + private static native void native_setLetterSpacing(long native_object, + float letterSpacing); } diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 11c25710d2e6..54683aa9268d 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -49,13 +49,11 @@ import java.util.ArrayList; * </p> * <li>Here is a simple VectorDrawable in this vectordrawable.xml file. * <pre> - * <vector xmlns:android="http://schemas.android.com/apk/res/android" > - * <size - * android:height="64dp" - * android:width="64dp" /> - * <viewport - * android:viewportHeight="600" - * android:viewportWidth="600" /> + * <vector xmlns:android="http://schemas.android.com/apk/res/android" + * android:height="64dp" + * android:width="64dp" + * android:viewportHeight="600" + * android:viewportWidth="600" > * <group * android:name="rotationGroup" * android:pivotX="300.0" @@ -63,7 +61,7 @@ import java.util.ArrayList; * android:rotation="45.0" > * <path * android:name="v" - * android:fill="#000000" + * android:fillColor="#000000" * android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> * </group> * </vector> diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java index 2d4936582a4a..6f21f2e00495 100644 --- a/graphics/java/android/graphics/drawable/Ripple.java +++ b/graphics/java/android/graphics/drawable/Ripple.java @@ -28,7 +28,6 @@ import android.graphics.Rect; import android.util.MathUtils; import android.view.HardwareCanvas; import android.view.RenderNodeAnimator; -import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import java.util.ArrayList; @@ -44,16 +43,14 @@ class Ripple { private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED; private static final float WAVE_TOUCH_UP_ACCELERATION = 3400.0f * GLOBAL_SPEED; private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED; - private static final float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED; - private static final float WAVE_OUTER_OPACITY_VELOCITY_MIN = 1.5f * GLOBAL_SPEED; - private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f; - private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f; private static final long RIPPLE_ENTER_DELAY = 80; // Hardware animators. - private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>(); - private final ArrayList<RenderNodeAnimator> mPendingAnimations = new ArrayList<>(); + private final ArrayList<RenderNodeAnimator> mRunningAnimations = + new ArrayList<RenderNodeAnimator>(); + private final ArrayList<RenderNodeAnimator> mPendingAnimations = + new ArrayList<RenderNodeAnimator>(); private final RippleDrawable mOwner; @@ -79,20 +76,17 @@ class Ripple { private CanvasProperty<Float> mPropRadius; private CanvasProperty<Float> mPropX; private CanvasProperty<Float> mPropY; - private CanvasProperty<Paint> mPropOuterPaint; - private CanvasProperty<Float> mPropOuterRadius; - private CanvasProperty<Float> mPropOuterX; - private CanvasProperty<Float> mPropOuterY; // Software animators. private ObjectAnimator mAnimRadius; private ObjectAnimator mAnimOpacity; - private ObjectAnimator mAnimOuterOpacity; private ObjectAnimator mAnimX; private ObjectAnimator mAnimY; + // Temporary paint used for creating canvas properties. + private Paint mTempPaint; + // Software rendering properties. - private float mOuterOpacity = 0; private float mOpacity = 1; private float mOuterX; private float mOuterY; @@ -177,38 +171,35 @@ class Ripple { return mOpacity; } - public void setOuterOpacity(float a) { - mOuterOpacity = a; - invalidateSelf(); - } - - public float getOuterOpacity() { - return mOuterOpacity; - } - + @SuppressWarnings("unused") public void setRadiusGravity(float r) { mTweenRadius = r; invalidateSelf(); } + @SuppressWarnings("unused") public float getRadiusGravity() { return mTweenRadius; } + @SuppressWarnings("unused") public void setXGravity(float x) { mTweenX = x; invalidateSelf(); } + @SuppressWarnings("unused") public float getXGravity() { return mTweenX; } + @SuppressWarnings("unused") public void setYGravity(float y) { mTweenY = y; invalidateSelf(); } + @SuppressWarnings("unused") public float getYGravity() { return mTweenY; } @@ -238,7 +229,7 @@ class Ripple { // If we have any pending hardware animations, cancel any running // animations and start those now. final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations; - final int N = pendingAnimations == null ? 0 : pendingAnimations.size(); + final int N = pendingAnimations.size(); if (N > 0) { cancelHardwareAnimations(); @@ -251,7 +242,6 @@ class Ripple { pendingAnimations.clear(); } - c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint); c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint); return true; @@ -262,15 +252,6 @@ class Ripple { // Cache the paint alpha so we can restore it later. final int paintAlpha = p.getAlpha(); - - final int outerAlpha = (int) (paintAlpha * mOuterOpacity + 0.5f); - if (outerAlpha > 0 && mOuterRadius > 0) { - p.setAlpha(outerAlpha); - p.setStyle(Style.FILL); - c.drawCircle(mOuterX, mOuterY, mOuterRadius, p); - hasContent = true; - } - final int alpha = (int) (paintAlpha * mOpacity + 0.5f); final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); if (alpha > 0 && radius > 0) { @@ -316,7 +297,6 @@ class Ripple { public void enter() { final int radiusDuration = (int) (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5); - final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN); final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1); radius.setAutoCancel(true); @@ -336,13 +316,7 @@ class Ripple { cY.setInterpolator(LINEAR_INTERPOLATOR); cY.setStartDelay(RIPPLE_ENTER_DELAY); - final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1); - outer.setAutoCancel(true); - outer.setDuration(outerDuration); - outer.setInterpolator(LINEAR_INTERPOLATOR); - mAnimRadius = radius; - mAnimOuterOpacity = outer; mAnimX = cX; mAnimY = cY; @@ -350,7 +324,6 @@ class Ripple { // that anything interesting is happening until the user lifts their // finger. radius.start(); - outer.start(); cX.start(); cY.start(); } @@ -372,51 +345,23 @@ class Ripple { + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5); final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f); - // Scale the outer max opacity and opacity velocity based - // on the size of the outer radius - - float outerSizeInfluence = MathUtils.constrain( - (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity) - / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1); - float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_VELOCITY_MIN, - WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence); - - // Determine at what time the inner and outer opacity intersect. - // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000 - // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000 - - final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity) - / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f)); - final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection - * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f); - if (mCanUseHardware) { - exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity); + exitHardware(radiusDuration, opacityDuration); } else { - exitSoftware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity); + exitSoftware(radiusDuration, opacityDuration); } } - private void exitHardware(int radiusDuration, int opacityDuration, int outerInflection, - int inflectionOpacity) { + private void exitHardware(int radiusDuration, int opacityDuration) { mPendingAnimations.clear(); final float startX = MathUtils.lerp( mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX); final float startY = MathUtils.lerp( mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY); - final Paint outerPaint = new Paint(); - outerPaint.setAntiAlias(true); - outerPaint.setColor(mColor); - outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f)); - outerPaint.setStyle(Style.FILL); - mPropOuterPaint = CanvasProperty.createPaint(outerPaint); - mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius); - mPropOuterX = CanvasProperty.createFloat(mOuterX); - mPropOuterY = CanvasProperty.createFloat(mOuterY); final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); - final Paint paint = new Paint(); + final Paint paint = getTempPaint(); paint.setAntiAlias(true); paint.setColor(mColor); paint.setAlpha((int) (255 * mOpacity + 0.5f)); @@ -442,41 +387,10 @@ class Ripple { RenderNodeAnimator.PAINT_ALPHA, 0); opacityAnim.setDuration(opacityDuration); opacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - - final RenderNodeAnimator outerOpacityAnim; - if (outerInflection > 0) { - // Outer opacity continues to increase for a bit. - outerOpacityAnim = new RenderNodeAnimator( - mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity); - outerOpacityAnim.setDuration(outerInflection); - outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - - // Chain the outer opacity exit animation. - final int outerDuration = opacityDuration - outerInflection; - if (outerDuration > 0) { - final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator( - mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0); - outerFadeOutAnim.setDuration(outerDuration); - outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR); - outerFadeOutAnim.setStartDelay(outerInflection); - outerFadeOutAnim.setStartValue(inflectionOpacity); - outerFadeOutAnim.addListener(mAnimationListener); - - mPendingAnimations.add(outerFadeOutAnim); - } else { - outerOpacityAnim.addListener(mAnimationListener); - } - } else { - outerOpacityAnim = new RenderNodeAnimator( - mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0); - outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - outerOpacityAnim.setDuration(opacityDuration); - outerOpacityAnim.addListener(mAnimationListener); - } + opacityAnim.addListener(mAnimationListener); mPendingAnimations.add(radiusAnim); mPendingAnimations.add(opacityAnim); - mPendingAnimations.add(outerOpacityAnim); mPendingAnimations.add(xAnim); mPendingAnimations.add(yAnim); @@ -485,8 +399,14 @@ class Ripple { invalidateSelf(); } - private void exitSoftware(int radiusDuration, int opacityDuration, int outerInflection, - int inflectionOpacity) { + private Paint getTempPaint() { + if (mTempPaint == null) { + mTempPaint = new Paint(); + } + return mTempPaint; + } + + private void exitSoftware(int radiusDuration, int opacityDuration) { final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radiusGravity", 1); radiusAnim.setAutoCancel(true); radiusAnim.setDuration(radiusDuration); @@ -506,58 +426,15 @@ class Ripple { opacityAnim.setAutoCancel(true); opacityAnim.setDuration(opacityDuration); opacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - - final ObjectAnimator outerOpacityAnim; - if (outerInflection > 0) { - // Outer opacity continues to increase for a bit. - outerOpacityAnim = ObjectAnimator.ofFloat(this, - "outerOpacity", inflectionOpacity / 255.0f); - outerOpacityAnim.setAutoCancel(true); - outerOpacityAnim.setDuration(outerInflection); - outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - - // Chain the outer opacity exit animation. - final int outerDuration = opacityDuration - outerInflection; - if (outerDuration > 0) { - outerOpacityAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - final ObjectAnimator outerFadeOutAnim = ObjectAnimator.ofFloat(Ripple.this, - "outerOpacity", 0); - outerFadeOutAnim.setAutoCancel(true); - outerFadeOutAnim.setDuration(outerDuration); - outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR); - outerFadeOutAnim.addListener(mAnimationListener); - - mAnimOuterOpacity = outerFadeOutAnim; - - outerFadeOutAnim.start(); - } - - @Override - public void onAnimationCancel(Animator animation) { - animation.removeListener(this); - } - }); - } else { - outerOpacityAnim.addListener(mAnimationListener); - } - } else { - outerOpacityAnim = ObjectAnimator.ofFloat(this, "outerOpacity", 0); - outerOpacityAnim.setAutoCancel(true); - outerOpacityAnim.setDuration(opacityDuration); - outerOpacityAnim.addListener(mAnimationListener); - } + opacityAnim.addListener(mAnimationListener); mAnimRadius = radiusAnim; mAnimOpacity = opacityAnim; - mAnimOuterOpacity = outerOpacityAnim; - mAnimX = opacityAnim; - mAnimY = opacityAnim; + mAnimX = xAnim; + mAnimY = yAnim; radiusAnim.start(); opacityAnim.start(); - outerOpacityAnim.start(); xAnim.start(); yAnim.start(); } @@ -579,10 +456,6 @@ class Ripple { mAnimOpacity.cancel(); } - if (mAnimOuterOpacity != null) { - mAnimOuterOpacity.cancel(); - } - if (mAnimX != null) { mAnimX.cancel(); } @@ -597,7 +470,7 @@ class Ripple { */ private void cancelHardwareAnimations() { final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations; - final int N = runningAnimations == null ? 0 : runningAnimations.size(); + final int N = runningAnimations.size(); for (int i = 0; i < N; i++) { runningAnimations.get(i).cancel(); } diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java new file mode 100644 index 000000000000..d404ccd8b1f2 --- /dev/null +++ b/graphics/java/android/graphics/drawable/RippleBackground.java @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.drawable; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; +import android.graphics.Canvas; +import android.graphics.CanvasProperty; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.Rect; +import android.util.MathUtils; +import android.view.HardwareCanvas; +import android.view.RenderNodeAnimator; +import android.view.animation.LinearInterpolator; + +import java.util.ArrayList; + +/** + * Draws a Material ripple. + */ +class RippleBackground { + private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); + private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator(); + + private static final float GLOBAL_SPEED = 1.0f; + private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED; + private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED; + private static final float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED; + private static final float WAVE_OUTER_OPACITY_VELOCITY_MIN = 1.5f * GLOBAL_SPEED; + private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f; + private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f; + + private static final long RIPPLE_ENTER_DELAY = 80; + + // Hardware animators. + private final ArrayList<RenderNodeAnimator> mRunningAnimations = + new ArrayList<RenderNodeAnimator>(); + private final ArrayList<RenderNodeAnimator> mPendingAnimations = + new ArrayList<RenderNodeAnimator>(); + + private final RippleDrawable mOwner; + + /** Bounds used for computing max radius. */ + private final Rect mBounds; + + /** Full-opacity color for drawing this ripple. */ + private int mColor; + + /** Maximum ripple radius. */ + private float mOuterRadius; + + /** Screen density used to adjust pixel-based velocities. */ + private float mDensity; + + private float mStartingX; + private float mStartingY; + private float mClampedStartingX; + private float mClampedStartingY; + + // Hardware rendering properties. + private CanvasProperty<Paint> mPropOuterPaint; + private CanvasProperty<Float> mPropOuterRadius; + private CanvasProperty<Float> mPropOuterX; + private CanvasProperty<Float> mPropOuterY; + + // Software animators. + private ObjectAnimator mAnimOuterOpacity; + private ObjectAnimator mAnimX; + private ObjectAnimator mAnimY; + + // Temporary paint used for creating canvas properties. + private Paint mTempPaint; + + // Software rendering properties. + private float mOuterOpacity = 0; + private float mOuterX; + private float mOuterY; + + // Values used to tween between the start and end positions. + private float mTweenX = 0; + private float mTweenY = 0; + + /** Whether we should be drawing hardware animations. */ + private boolean mHardwareAnimating; + + /** Whether we can use hardware acceleration for the exit animation. */ + private boolean mCanUseHardware; + + /** Whether we have an explicit maximum radius. */ + private boolean mHasMaxRadius; + + /** + * Creates a new ripple. + */ + public RippleBackground(RippleDrawable owner, Rect bounds, float startingX, float startingY) { + mOwner = owner; + mBounds = bounds; + + mStartingX = startingX; + mStartingY = startingY; + } + + public void setup(int maxRadius, int color, float density) { + mColor = color | 0xFF000000; + + if (maxRadius != RippleDrawable.RADIUS_AUTO) { + mHasMaxRadius = true; + mOuterRadius = maxRadius; + } else { + final float halfWidth = mBounds.width() / 2.0f; + final float halfHeight = mBounds.height() / 2.0f; + mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); + } + + mOuterX = 0; + mOuterY = 0; + mDensity = density; + + clampStartingPosition(); + } + + private void clampStartingPosition() { + final float cX = mBounds.exactCenterX(); + final float cY = mBounds.exactCenterY(); + final float dX = mStartingX - cX; + final float dY = mStartingY - cY; + final float r = mOuterRadius; + if (dX * dX + dY * dY > r * r) { + // Point is outside the circle, clamp to the circumference. + final double angle = Math.atan2(dY, dX); + mClampedStartingX = cX + (float) (Math.cos(angle) * r); + mClampedStartingY = cY + (float) (Math.sin(angle) * r); + } else { + mClampedStartingX = mStartingX; + mClampedStartingY = mStartingY; + } + } + + public void onHotspotBoundsChanged() { + if (!mHasMaxRadius) { + final float halfWidth = mBounds.width() / 2.0f; + final float halfHeight = mBounds.height() / 2.0f; + mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); + + clampStartingPosition(); + } + } + + @SuppressWarnings("unused") + public void setOuterOpacity(float a) { + mOuterOpacity = a; + invalidateSelf(); + } + + @SuppressWarnings("unused") + public float getOuterOpacity() { + return mOuterOpacity; + } + + @SuppressWarnings("unused") + public void setXGravity(float x) { + mTweenX = x; + invalidateSelf(); + } + + @SuppressWarnings("unused") + public float getXGravity() { + return mTweenX; + } + + @SuppressWarnings("unused") + public void setYGravity(float y) { + mTweenY = y; + invalidateSelf(); + } + + @SuppressWarnings("unused") + public float getYGravity() { + return mTweenY; + } + + /** + * Draws the ripple centered at (0,0) using the specified paint. + */ + public boolean draw(Canvas c, Paint p) { + final boolean canUseHardware = c.isHardwareAccelerated(); + if (mCanUseHardware != canUseHardware && mCanUseHardware) { + // We've switched from hardware to non-hardware mode. Panic. + cancelHardwareAnimations(); + } + mCanUseHardware = canUseHardware; + + final boolean hasContent; + if (canUseHardware && mHardwareAnimating) { + hasContent = drawHardware((HardwareCanvas) c); + } else { + hasContent = drawSoftware(c, p); + } + + return hasContent; + } + + private boolean drawHardware(HardwareCanvas c) { + // If we have any pending hardware animations, cancel any running + // animations and start those now. + final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations; + final int N = pendingAnimations.size(); + if (N > 0) { + cancelHardwareAnimations(); + + for (int i = 0; i < N; i++) { + pendingAnimations.get(i).setTarget(c); + pendingAnimations.get(i).start(); + } + + mRunningAnimations.addAll(pendingAnimations); + pendingAnimations.clear(); + } + + c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint); + + return true; + } + + private boolean drawSoftware(Canvas c, Paint p) { + boolean hasContent = false; + + // Cache the paint alpha so we can restore it later. + final int paintAlpha = p.getAlpha(); + + final int outerAlpha = (int) (paintAlpha * mOuterOpacity + 0.5f); + if (outerAlpha > 0 && mOuterRadius > 0) { + p.setAlpha(outerAlpha); + p.setStyle(Style.FILL); + c.drawCircle(mOuterX, mOuterY, mOuterRadius, p); + hasContent = true; + } + + p.setAlpha(paintAlpha); + + return hasContent; + } + + /** + * Returns the maximum bounds of the ripple relative to the ripple center. + */ + public void getBounds(Rect bounds) { + final int outerX = (int) mOuterX; + final int outerY = (int) mOuterY; + final int r = (int) mOuterRadius; + bounds.set(outerX - r, outerY - r, outerX + r, outerY + r); + } + + /** + * Specifies the starting position relative to the drawable bounds. No-op if + * the ripple has already entered. + */ + public void move(float x, float y) { + mStartingX = x; + mStartingY = y; + + clampStartingPosition(); + } + + /** + * Starts the enter animation. + */ + public void enter() { + final int radiusDuration = (int) + (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5); + final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN); + + final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "xGravity", 1); + cX.setAutoCancel(true); + cX.setDuration(radiusDuration); + cX.setInterpolator(LINEAR_INTERPOLATOR); + cX.setStartDelay(RIPPLE_ENTER_DELAY); + + final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "yGravity", 1); + cY.setAutoCancel(true); + cY.setDuration(radiusDuration); + cY.setInterpolator(LINEAR_INTERPOLATOR); + cY.setStartDelay(RIPPLE_ENTER_DELAY); + + final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1); + outer.setAutoCancel(true); + outer.setDuration(outerDuration); + outer.setInterpolator(LINEAR_INTERPOLATOR); + + mAnimOuterOpacity = outer; + mAnimX = cX; + mAnimY = cY; + + // Enter animations always run on the UI thread, since it's unlikely + // that anything interesting is happening until the user lifts their + // finger. + outer.start(); + cX.start(); + cY.start(); + } + + /** + * Starts the exit animation. + */ + public void exit() { + cancelSoftwareAnimations(); + + // Scale the outer max opacity and opacity velocity based + // on the size of the outer radius. + final int opacityDuration = (int) (1000 / WAVE_OPACITY_DECAY_VELOCITY + 0.5f); + final float outerSizeInfluence = MathUtils.constrain( + (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity) + / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1); + final float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_VELOCITY_MIN, + WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence); + + // Determine at what time the inner and outer opacity intersect. + // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000 + // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000 + final int outerInflection = Math.max(0, (int) (1000 * (1 - mOuterOpacity) + / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f)); + final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection + * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f); + + if (mCanUseHardware) { + exitHardware(opacityDuration, outerInflection, inflectionOpacity); + } else { + exitSoftware(opacityDuration, outerInflection, inflectionOpacity); + } + } + + private void exitHardware(int opacityDuration, int outerInflection, int inflectionOpacity) { + mPendingAnimations.clear(); + + // TODO: Adjust background by starting position. + final float startX = MathUtils.lerp( + mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX); + final float startY = MathUtils.lerp( + mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY); + + final Paint outerPaint = getTempPaint(); + outerPaint.setAntiAlias(true); + outerPaint.setColor(mColor); + outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f)); + outerPaint.setStyle(Style.FILL); + mPropOuterPaint = CanvasProperty.createPaint(outerPaint); + mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius); + mPropOuterX = CanvasProperty.createFloat(mOuterX); + mPropOuterY = CanvasProperty.createFloat(mOuterY); + + final RenderNodeAnimator outerOpacityAnim; + if (outerInflection > 0) { + // Outer opacity continues to increase for a bit. + outerOpacityAnim = new RenderNodeAnimator( + mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity); + outerOpacityAnim.setDuration(outerInflection); + outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); + + // Chain the outer opacity exit animation. + final int outerDuration = opacityDuration - outerInflection; + if (outerDuration > 0) { + final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator( + mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0); + outerFadeOutAnim.setDuration(outerDuration); + outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR); + outerFadeOutAnim.setStartDelay(outerInflection); + outerFadeOutAnim.setStartValue(inflectionOpacity); + outerFadeOutAnim.addListener(mAnimationListener); + + mPendingAnimations.add(outerFadeOutAnim); + } else { + outerOpacityAnim.addListener(mAnimationListener); + } + } else { + outerOpacityAnim = new RenderNodeAnimator( + mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0); + outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); + outerOpacityAnim.setDuration(opacityDuration); + outerOpacityAnim.addListener(mAnimationListener); + } + + mPendingAnimations.add(outerOpacityAnim); + + mHardwareAnimating = true; + + invalidateSelf(); + } + + private Paint getTempPaint() { + if (mTempPaint == null) { + mTempPaint = new Paint(); + } + return mTempPaint; + } + + private void exitSoftware(int opacityDuration, int outerInflection, int inflectionOpacity) { + final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1); + xAnim.setAutoCancel(true); + xAnim.setDuration(opacityDuration); + xAnim.setInterpolator(DECEL_INTERPOLATOR); + + final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1); + yAnim.setAutoCancel(true); + yAnim.setDuration(opacityDuration); + yAnim.setInterpolator(DECEL_INTERPOLATOR); + + final ObjectAnimator outerOpacityAnim; + if (outerInflection > 0) { + // Outer opacity continues to increase for a bit. + outerOpacityAnim = ObjectAnimator.ofFloat(this, + "outerOpacity", inflectionOpacity / 255.0f); + outerOpacityAnim.setAutoCancel(true); + outerOpacityAnim.setDuration(outerInflection); + outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); + + // Chain the outer opacity exit animation. + final int outerDuration = opacityDuration - outerInflection; + if (outerDuration > 0) { + outerOpacityAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + final ObjectAnimator outerFadeOutAnim = ObjectAnimator.ofFloat( + RippleBackground.this, "outerOpacity", 0); + outerFadeOutAnim.setAutoCancel(true); + outerFadeOutAnim.setDuration(outerDuration); + outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR); + outerFadeOutAnim.addListener(mAnimationListener); + + mAnimOuterOpacity = outerFadeOutAnim; + + outerFadeOutAnim.start(); + } + + @Override + public void onAnimationCancel(Animator animation) { + animation.removeListener(this); + } + }); + } else { + outerOpacityAnim.addListener(mAnimationListener); + } + } else { + outerOpacityAnim = ObjectAnimator.ofFloat(this, "outerOpacity", 0); + outerOpacityAnim.setAutoCancel(true); + outerOpacityAnim.setDuration(opacityDuration); + outerOpacityAnim.addListener(mAnimationListener); + } + + mAnimOuterOpacity = outerOpacityAnim; + mAnimX = xAnim; + mAnimY = yAnim; + + outerOpacityAnim.start(); + xAnim.start(); + yAnim.start(); + } + + /** + * Cancel all animations. + */ + public void cancel() { + cancelSoftwareAnimations(); + cancelHardwareAnimations(); + } + + private void cancelSoftwareAnimations() { + if (mAnimOuterOpacity != null) { + mAnimOuterOpacity.cancel(); + } + + if (mAnimX != null) { + mAnimX.cancel(); + } + + if (mAnimY != null) { + mAnimY.cancel(); + } + } + + /** + * Cancels any running hardware animations. + */ + private void cancelHardwareAnimations() { + final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations; + final int N = runningAnimations.size(); + for (int i = 0; i < N; i++) { + runningAnimations.get(i).cancel(); + } + + runningAnimations.clear(); + } + + private void removeSelf() { + // The owner will invalidate itself. + mOwner.removeBackground(this); + } + + private void invalidateSelf() { + mOwner.invalidateSelf(); + } + + private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + removeSelf(); + } + }; + + /** + * Interpolator with a smooth log deceleration + */ + private static final class LogInterpolator implements TimeInterpolator { + @Override + public float getInterpolation(float input) { + return 1 - (float) Math.pow(400, -input * 1.4); + } + } +} diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index e23928cc3365..0c9c5584ac8e 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -120,8 +120,22 @@ public class RippleDrawable extends LayerDrawable { /** The masking layer, e.g. the layer with id R.id.mask. */ private Drawable mMask; - /** The current hotspot. May be actively animating or pending entry. */ - private Ripple mHotspot; + /** The current background. May be actively animating or pending entry. */ + private RippleBackground mBackground; + + /** Whether we expect to draw a background when visible. */ + private boolean mBackgroundActive; + + /** The current ripple. May be actively animating or pending entry. */ + private Ripple mRipple; + + /** Whether we expect to draw a ripple when visible. */ + private boolean mRippleActive; + + // Hotspot coordinates that are awaiting activation. + private float mPendingX; + private float mPendingY; + private boolean mHasPending; /** * Lazily-created array of actively animating ripples. Inactive ripples are @@ -142,9 +156,6 @@ public class RippleDrawable extends LayerDrawable { /** Whether bounds are being overridden. */ private boolean mOverrideBounds; - /** Whether the hotspot is currently active (e.g. focused or pressed). */ - private boolean mActive; - /** * Constructor used for drawable inflation. */ @@ -205,20 +216,26 @@ public class RippleDrawable extends LayerDrawable { protected boolean onStateChange(int[] stateSet) { super.onStateChange(stateSet); - // TODO: This would make more sense in a StateListDrawable. - boolean active = false; boolean enabled = false; + boolean pressed = false; + boolean focused = false; + final int N = stateSet.length; for (int i = 0; i < N; i++) { if (stateSet[i] == R.attr.state_enabled) { enabled = true; } if (stateSet[i] == R.attr.state_focused - || stateSet[i] == R.attr.state_pressed) { - active = true; + || stateSet[i] == R.attr.state_selected) { + focused = true; + } + if (stateSet[i] == R.attr.state_pressed) { + pressed = true; } } - setActive(active && enabled); + + setRippleActive(enabled && pressed); + setBackgroundActive(focused || (enabled && pressed)); // Update the paint color. Only applicable when animated in software. if (mRipplePaint != null && mState.mColor != null) { @@ -235,14 +252,24 @@ public class RippleDrawable extends LayerDrawable { return false; } - private void setActive(boolean active) { - if (mActive != active) { - mActive = active; + private void setRippleActive(boolean active) { + if (mRippleActive != active) { + mRippleActive = active; + if (active) { + activateRipple(); + } else { + removeRipple(); + } + } + } + private void setBackgroundActive(boolean active) { + if (mBackgroundActive != active) { + mBackgroundActive = active; if (active) { - activateHotspot(); + activateBackground(); } else { - removeHotspot(); + removeBackground(); } } } @@ -261,11 +288,23 @@ public class RippleDrawable extends LayerDrawable { @Override public boolean setVisible(boolean visible, boolean restart) { + final boolean changed = super.setVisible(visible, restart); + if (!visible) { clearHotspots(); + } else if (changed) { + // If we just became visible, ensure the background and ripple + // visibilities are consistent with their internal states. + if (mRippleActive) { + activateRipple(); + } + + if (mBackgroundActive) { + activateBackground(); + } } - return super.setVisible(visible, restart); + return changed; } /** @@ -399,55 +438,101 @@ public class RippleDrawable extends LayerDrawable { @Override public void setHotspot(float x, float y) { - if (mHotspot == null) { - mHotspot = new Ripple(this, mHotspotBounds, x, y); + if (mRipple == null || mBackground == null) { + mPendingX = x; + mPendingY = y; + mHasPending = true; + } + + if (mRipple != null) { + mRipple.move(x, y); + } - if (mActive) { - activateHotspot(); + if (mBackground != null) { + mBackground.move(x, y); + } + } + + /** + * Creates an active hotspot at the specified location. + */ + private void activateBackground() { + if (mBackground == null) { + final float x; + final float y; + if (mHasPending) { + mHasPending = false; + x = mPendingX; + y = mPendingY; + } else { + x = mHotspotBounds.exactCenterX(); + y = mHotspotBounds.exactCenterY(); } - } else { - mHotspot.move(x, y); + mBackground = new RippleBackground(this, mHotspotBounds, x, y); + } + + final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT); + mBackground.setup(mState.mMaxRadius, color, mDensity); + mBackground.enter(); + } + + private void removeBackground() { + if (mBackground != null) { + // Don't null out the background, we need it to draw! + mBackground.exit(); } } /** * Creates an active hotspot at the specified location. */ - private void activateHotspot() { + private void activateRipple() { if (mAnimatingRipplesCount >= MAX_RIPPLES) { // This should never happen unless the user is tapping like a maniac // or there is a bug that's preventing ripples from being removed. - Log.d(LOG_TAG, "Max ripple count exceeded", new RuntimeException()); return; } - if (mHotspot == null) { - final float x = mHotspotBounds.exactCenterX(); - final float y = mHotspotBounds.exactCenterY(); - mHotspot = new Ripple(this, mHotspotBounds, x, y); + if (mRipple == null) { + final float x; + final float y; + if (mHasPending) { + mHasPending = false; + x = mPendingX; + y = mPendingY; + } else { + x = mHotspotBounds.exactCenterX(); + y = mHotspotBounds.exactCenterY(); + } + mRipple = new Ripple(this, mHotspotBounds, x, y); } final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT); - mHotspot.setup(mState.mMaxRadius, color, mDensity); - mHotspot.enter(); + mRipple.setup(mState.mMaxRadius, color, mDensity); + mRipple.enter(); if (mAnimatingRipples == null) { mAnimatingRipples = new Ripple[MAX_RIPPLES]; } - mAnimatingRipples[mAnimatingRipplesCount++] = mHotspot; + mAnimatingRipples[mAnimatingRipplesCount++] = mRipple; } - private void removeHotspot() { - if (mHotspot != null) { - mHotspot.exit(); - mHotspot = null; + private void removeRipple() { + if (mRipple != null) { + mRipple.exit(); + mRipple = null; } } private void clearHotspots() { - if (mHotspot != null) { - mHotspot.cancel(); - mHotspot = null; + if (mRipple != null) { + mRipple.cancel(); + mRipple = null; + } + + if (mBackground != null) { + mBackground.cancel(); + mBackground = null; } final int count = mAnimatingRipplesCount; @@ -487,6 +572,10 @@ public class RippleDrawable extends LayerDrawable { for (int i = 0; i < count; i++) { ripples[i].onHotspotBoundsChanged(); } + + if (mBackground != null) { + mBackground.onHotspotBoundsChanged(); + } } /** @@ -525,18 +614,28 @@ public class RippleDrawable extends LayerDrawable { // Next, try to draw the ripples (into a layer if necessary). If we need // to mask against the underlying content, set the xfermode to SRC_ATOP. final PorterDuffXfermode xfermode = (hasMask || !drawNonMaskContent) ? SRC_OVER : SRC_ATOP; - final int rippleLayer = drawRippleLayer(canvas, bounds, xfermode); + + // If we have a background and a non-opaque mask, draw the masking layer. + final int backgroundLayer = drawBackgroundLayer(canvas, bounds, xfermode); + if (backgroundLayer >= 0) { + if (drawMask) { + drawMaskingLayer(canvas, bounds, DST_IN); + } + canvas.restoreToCount(backgroundLayer); + } // If we have ripples and a non-opaque mask, draw the masking layer. - if (rippleLayer >= 0 && drawMask) { - drawMaskingLayer(canvas, bounds, DST_IN); + final int rippleLayer = drawRippleLayer(canvas, bounds, xfermode); + if (rippleLayer >= 0) { + if (drawMask) { + drawMaskingLayer(canvas, bounds, DST_IN); + } + canvas.restoreToCount(rippleLayer); } // Composite the layers if needed. if (contentLayer >= 0) { canvas.restoreToCount(contentLayer); - } else if (rippleLayer >= 0) { - canvas.restoreToCount(rippleLayer); } } @@ -551,15 +650,20 @@ public class RippleDrawable extends LayerDrawable { final int count = mAnimatingRipplesCount; final int index = getRippleIndex(ripple); if (index >= 0) { - for (int i = index + 1; i < count; i++) { - ripples[i - 1] = ripples[i]; - } + System.arraycopy(ripples, index + 1, ripples, index + 1 - 1, count - (index + 1)); ripples[count - 1] = null; mAnimatingRipplesCount--; invalidateSelf(); } } + void removeBackground(RippleBackground background) { + if (mBackground == background) { + mBackground = null; + invalidateSelf(); + } + } + private int getRippleIndex(Ripple ripple) { final Ripple[] ripples = mAnimatingRipples; final int count = mAnimatingRipplesCount; @@ -578,7 +682,7 @@ public class RippleDrawable extends LayerDrawable { // We don't need a layer if we don't expect to draw any ripples, we have // an explicit mask, or if the non-mask content is all opaque. boolean needsLayer = false; - if (mAnimatingRipplesCount > 0 && mMask == null) { + if ((mAnimatingRipplesCount > 0 || mBackground != null) && mMask == null) { for (int i = 0; i < count; i++) { if (array[i].mId != R.id.mask && array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) { @@ -602,12 +706,62 @@ public class RippleDrawable extends LayerDrawable { return restoreToCount; } - private int drawRippleLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) { - final int count = mAnimatingRipplesCount; - if (count == 0) { - return -1; + private int drawBackgroundLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) { + // Separate the ripple color and alpha channel. The alpha will be + // applied when we merge the ripples down to the canvas. + final int rippleARGB; + if (mState.mColor != null) { + rippleARGB = mState.mColor.getColorForState(getState(), Color.TRANSPARENT); + } else { + rippleARGB = Color.TRANSPARENT; + } + + if (mRipplePaint == null) { + mRipplePaint = new Paint(); + mRipplePaint.setAntiAlias(true); + } + + final int rippleAlpha = Color.alpha(rippleARGB); + final Paint ripplePaint = mRipplePaint; + ripplePaint.setColor(rippleARGB); + ripplePaint.setAlpha(0xFF); + + boolean drewRipples = false; + int restoreToCount = -1; + int restoreTranslate = -1; + + // Draw background. + final RippleBackground background = mBackground; + if (background != null) { + // If we're masking the ripple layer, make sure we have a layer + // first. This will merge SRC_OVER (directly) onto the canvas. + final Paint maskingPaint = getMaskingPaint(mode); + maskingPaint.setAlpha(rippleAlpha); + restoreToCount = canvas.saveLayer(bounds.left, bounds.top, + bounds.right, bounds.bottom, maskingPaint); + + restoreTranslate = canvas.save(); + // Translate the canvas to the current hotspot bounds. + canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY()); + + drewRipples = background.draw(canvas, ripplePaint); } + // Always restore the translation. + if (restoreTranslate >= 0) { + canvas.restoreToCount(restoreTranslate); + } + + // If we created a layer with no content, merge it immediately. + if (restoreToCount >= 0 && !drewRipples) { + canvas.restoreToCount(restoreToCount); + restoreToCount = -1; + } + + return restoreToCount; + } + + private int drawRippleLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) { // Separate the ripple color and alpha channel. The alpha will be // applied when we merge the ripples down to the canvas. final int rippleARGB; @@ -632,6 +786,7 @@ public class RippleDrawable extends LayerDrawable { int restoreTranslate = -1; // Draw ripples and update the animating ripples array. + final int count = mAnimatingRipplesCount; final Ripple[] ripples = mAnimatingRipples; for (int i = 0; i < count; i++) { final Ripple ripple = ripples[i]; @@ -706,6 +861,13 @@ public class RippleDrawable extends LayerDrawable { drawingBounds.union(rippleBounds); } + final RippleBackground background = mBackground; + if (background != null) { + background.getBounds(rippleBounds); + rippleBounds.offset(cX, cY); + drawingBounds.union(rippleBounds); + } + dirtyBounds.union(drawingBounds); dirtyBounds.union(super.getDirtyBounds()); return dirtyBounds; diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 8ed6776d395a..f41b11a6ef40 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -54,76 +54,130 @@ import java.util.Stack; * <p/> * The vector drawable has the following elements: * <p/> - * <dl> * <dt><code><vector></code></dt> - * <dd>Used to defined a vector drawable</dd> - * <dt><code><size></code></dt> - * <dd>Used to defined the intrinsic Width Height size of the drawable using - * <code>android:width</code> and <code>android:height</code></dd> - * <dt><code><viewport></code></dt> - * <dd>Used to defined the size of the virtual canvas the paths are drawn on. - * The size is defined using the attributes <code>android:viewportHeight</code> - * <code>android:viewportWidth</code></dd> + * <dl> + * <dd>Used to defined a vector drawable + * <dl> + * <dt><code>android:width</code></dt> + * <dd>Used to defined the intrinsic width of the drawable. + * This support all the dimension units, normally specified with dp.</dd> + * <dt><code>android:height</code></dt> + * <dd>Used to defined the intrinsic height the drawable. + * This support all the dimension units, normally specified with dp.</dd> + * <dt><code>android:viewportWidth</code></dt> + * <dd>Used to defined the width of the viewport space. Viewport is basically + * the virtual canvas where the paths are drawn on.</dd> + * <dt><code>android:viewportHeight</code></dt> + * <dd>Used to defined the height of the viewport space. Viewport is basically + * the virtual canvas where the paths are drawn on.</dd> + * <dt><code>android:tint</code></dt> + * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd> + * <dt><code>android:tintMode</code></dt> + * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd> + * <dt><code>android:autoMirrored</code></dt> + * <dd>Indicates if the drawable needs to be mirrored when its layout direction is + * RTL (right-to-left).</dd> + * </dl></dd> + * </dl> + * + * <dl> * <dt><code><group></code></dt> * <dd>Defines a group of paths or subgroups, plus transformation information. * The transformations are defined in the same coordinates as the viewport. - * And the transformations are applied in the order of scale, rotate then translate. </dd> - * <dt><code>android:rotation</code> - * <dd>The degrees of rotation of the group.</dd></dt> - * <dt><code>android:pivotX</code> - * <dd>The X coordinate of the pivot for the scale and rotation of the group</dd></dt> - * <dt><code>android:pivotY</code> - * <dd>The Y coordinate of the pivot for the scale and rotation of the group</dd></dt> - * <dt><code>android:scaleX</code> - * <dd>The amount of scale on the X Coordinate</dd></dt> - * <dt><code>android:scaleY</code> - * <dd>The amount of scale on the Y coordinate</dd></dt> - * <dt><code>android:translateX</code> - * <dd>The amount of translation on the X coordinate</dd></dt> - * <dt><code>android:translateY</code> - * <dd>The amount of translation on the Y coordinate</dd></dt> + * And the transformations are applied in the order of scale, rotate then translate. + * <dl> + * <dt><code>android:rotation</code></dt> + * <dd>The degrees of rotation of the group.</dd> + * <dt><code>android:pivotX</code></dt> + * <dd>The X coordinate of the pivot for the scale and rotation of the group. + * This is defined in the viewport space.</dd> + * <dt><code>android:pivotY</code></dt> + * <dd>The Y coordinate of the pivot for the scale and rotation of the group. + * This is defined in the viewport space.</dd> + * <dt><code>android:scaleX</code></dt> + * <dd>The amount of scale on the X Coordinate.</dd> + * <dt><code>android:scaleY</code></dt> + * <dd>The amount of scale on the Y coordinate.</dd> + * <dt><code>android:translateX</code></dt> + * <dd>The amount of translation on the X coordinate. + * This is defined in the viewport space.</dd> + * <dt><code>android:translateY</code></dt> + * <dd>The amount of translation on the Y coordinate. + * This is defined in the viewport space.</dd> + * </dl></dd> + * </dl> + * + * <dl> * <dt><code><path></code></dt> * <dd>Defines paths to be drawn. * <dl> - * <dt><code>android:name</code> - * <dd>Defines the name of the path.</dd></dt> - * <dt><code>android:pathData</code> + * <dt><code>android:name</code></dt> + * <dd>Defines the name of the path.</dd> + * <dt><code>android:pathData</code></dt> * <dd>Defines path string. This is using exactly same format as "d" attribute - * in the SVG's path data</dd></dt> - * <dt><code>android:fill</code> - * <dd>Defines the color to fill the path (none if not present).</dd></dt> - * <dt><code>android:stroke</code> + * in the SVG's path data. This is defined in the viewport space.</dd> + * <dt><code>android:fillColor</code></dt> + * <dd>Defines the color to fill the path (none if not present).</dd> + * <dt><code>android:strokeColor</code></dt> * <dd>Defines the color to draw the path outline (none if not present).</dd> - * </dt> - * <dt><code>android:strokeWidth</code> - * <dd>The width a path stroke</dd></dt> - * <dt><code>android:strokeOpacity</code> - * <dd>The opacity of a path stroke</dd></dt> - * <dt><code>android:fillOpacity</code> - * <dd>The opacity to fill the path with</dd></dt> - * <dt><code>android:trimPathStart</code> - * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt> - * <dt><code>android:trimPathEnd</code> - * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt> - * <dt><code>android:trimPathOffset</code> - * <dd>Shift trim region (allows showed region to include the start and end) - * from 0 to 1</dd></dt> - * <dt><code>android:clipToPath</code> - * <dd>Path will set the clip path</dd></dt> - * <dt><code>android:strokeLineCap</code> - * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt> - * <dt><code>android:strokeLineJoin</code> - * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt> - * <dt><code>android:strokeMiterLimit</code> - * <dd>Sets the Miter limit for a stroked path</dd></dt> + * <dt><code>android:strokeWidth</code></dt> + * <dd>The width a path stroke.</dd> + * <dt><code>android:strokeOpacity</code></dt> + * <dd>The opacity of a path stroke.</dd> + * <dt><code>android:fillOpacity</code></dt> + * <dd>The opacity to fill the path with.</dd> + * <dt><code>android:trimPathStart</code></dt> + * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd> + * <dt><code>android:trimPathEnd</code></dt> + * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd> + * <dt><code>android:trimPathOffset</code></dt> + * <dd>Shift trim region (allows showed region to include the start and end), in the range + * from 0 to 1.</dd> + * <dt><code>android:strokeLineCap</code></dt> + * <dd>Sets the linecap for a stroked path: butt, round, square.</dd> + * <dt><code>android:strokeLineJoin</code></dt> + * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd> + * <dt><code>android:strokeMiterLimit</code></dt> + * <dd>Sets the Miter limit for a stroked path.</dd> + * </dl></dd> + * </dl> + * + * <dl> + * <dt><code><clip-path></code></dt> + * <dd>Defines path to be the current clip. + * <dl> + * <dt><code>android:name</code></dt> + * <dd>Defines the name of the clip path.</dd> + * <dt><code>android:pathData</code></dt> + * <dd>Defines clip path string. This is using exactly same format as "d" attribute + * in the SVG's path data.</dd> + * </dl></dd> * </dl> - * </dd> + * <li>Here is a simple VectorDrawable in this vectordrawable.xml file. + * <pre> + * <vector xmlns:android="http://schemas.android.com/apk/res/android" + * android:height="64dp" + * android:width="64dp" + * android:viewportHeight="600" + * android:viewportWidth="600" > + * <group + * android:name="rotationGroup" + * android:pivotX="300.0" + * android:pivotY="300.0" + * android:rotation="45.0" > + * <path + * android:name="v" + * android:fillColor="#000000" + * android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + * </group> + * </vector> + * </pre></li> */ + public class VectorDrawable extends Drawable { private static final String LOGTAG = VectorDrawable.class.getSimpleName(); - private static final String SHAPE_SIZE = "size"; - private static final String SHAPE_VIEWPORT = "viewport"; + private static final String SHAPE_CLIP_PATH = "clip-path"; private static final String SHAPE_GROUP = "group"; private static final String SHAPE_PATH = "path"; private static final String SHAPE_VECTOR = "vector"; @@ -188,6 +242,12 @@ public class VectorDrawable extends Drawable { public void draw(Canvas canvas) { final int saveCount = canvas.save(); final Rect bounds = getBounds(); + + if (bounds.width() == 0 || bounds.height() == 0) { + // too small to draw + return; + } + final boolean needMirroring = needMirroring(); canvas.translate(bounds.left, bounds.top); @@ -331,20 +391,24 @@ public class VectorDrawable extends Drawable { @Override public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { - final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable); + final VectorDrawableState state = mVectorState; + final VPathRenderer pathRenderer = new VPathRenderer(); + state.mVPathRenderer = pathRenderer; + + TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable); updateStateFromTypedArray(a); a.recycle(); - final VectorDrawableState state = mVectorState; - mVectorState.mCacheDirty = true; + state.mCacheDirty = true; inflateInternal(res, parser, attrs, theme); mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); state.mVPathRenderer.setColorFilter(mTintFilter); } - private void updateStateFromTypedArray(TypedArray a) { + private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { final VectorDrawableState state = mVectorState; + final VPathRenderer pathRenderer = state.mVPathRenderer; // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); @@ -364,16 +428,38 @@ public class VectorDrawable extends Drawable { state.mAutoMirrored = a.getBoolean( R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored); + + pathRenderer.mViewportWidth = a.getFloat( + R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth); + pathRenderer.mViewportHeight = a.getFloat( + R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight); + + if (pathRenderer.mViewportWidth <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<viewport> tag requires viewportWidth > 0"); + } else if (pathRenderer.mViewportHeight <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<viewport> tag requires viewportHeight > 0"); + } + + pathRenderer.mBaseWidth = a.getDimension( + R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth); + pathRenderer.mBaseHeight = a.getDimension( + R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight); + + if (pathRenderer.mBaseWidth <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<size> tag requires width > 0"); + } else if (pathRenderer.mBaseHeight <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<size> tag requires height > 0"); + } } private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { final VectorDrawableState state = mVectorState; - final VPathRenderer pathRenderer = new VPathRenderer(); - state.mVPathRenderer = pathRenderer; - - boolean noSizeTag = true; - boolean noViewportTag = true; + final VPathRenderer pathRenderer = state.mVPathRenderer; boolean noPathTag = true; // Use a stack to help to build the group tree. @@ -388,7 +474,7 @@ public class VectorDrawable extends Drawable { final VGroup currentGroup = groupStack.peek(); if (SHAPE_PATH.equals(tagName)) { - final VPath path = new VPath(); + final VFullPath path = new VFullPath(); path.inflate(res, attrs, theme); currentGroup.mChildren.add(path); if (path.getPathName() != null) { @@ -396,14 +482,14 @@ public class VectorDrawable extends Drawable { } noPathTag = false; state.mChangingConfigurations |= path.mChangingConfigurations; - } else if (SHAPE_SIZE.equals(tagName)) { - pathRenderer.parseSize(res, attrs); - noSizeTag = false; - state.mChangingConfigurations |= pathRenderer.mChangingConfigurations; - } else if (SHAPE_VIEWPORT.equals(tagName)) { - pathRenderer.parseViewport(res, attrs); - noViewportTag = false; - state.mChangingConfigurations |= pathRenderer.mChangingConfigurations; + } else if (SHAPE_CLIP_PATH.equals(tagName)) { + final VClipPath path = new VClipPath(); + path.inflate(res, attrs, theme); + currentGroup.mChildren.add(path); + if (path.getPathName() != null) { + pathRenderer.mVGTargetsMap.put(path.getPathName(), path); + } + state.mChangingConfigurations |= path.mChangingConfigurations; } else if (SHAPE_GROUP.equals(tagName)) { VGroup newChildGroup = new VGroup(); newChildGroup.inflate(res, attrs, theme); @@ -429,26 +515,13 @@ public class VectorDrawable extends Drawable { printGroupTree(pathRenderer.mRootGroup, 0); } - if (noSizeTag || noViewportTag || noPathTag) { + if (noPathTag) { final StringBuffer tag = new StringBuffer(); - if (noSizeTag) { - tag.append(SHAPE_SIZE); - } - - if (noViewportTag) { - if (tag.length() > 0) { - tag.append(" & "); - } - tag.append(SHAPE_SIZE); - } - - if (noPathTag) { - if (tag.length() > 0) { - tag.append(" or "); - } - tag.append(SHAPE_PATH); + if (tag.length() > 0) { + tag.append(" or "); } + tag.append(SHAPE_PATH); throw new XmlPullParserException("no " + tag + " defined"); } @@ -605,10 +678,10 @@ public class VectorDrawable extends Drawable { // Variables below need to be copied (deep copy if applicable) for mutation. private int mChangingConfigurations; private final VGroup mRootGroup; - private float mBaseWidth = 0; - private float mBaseHeight = 0; - private float mViewportWidth = 0; - private float mViewportHeight = 0; + float mBaseWidth = 0; + float mBaseHeight = 0; + float mViewportWidth = 0; + float mViewportHeight = 0; private int mRootAlpha = 0xFF; final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>(); @@ -730,7 +803,8 @@ public class VectorDrawable extends Drawable { public void draw(Canvas canvas, int w, int h) { // Travese the tree in pre-order to draw. - drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF, canvas, w, h); + drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF, + canvas, w, h); } private void drawPath(VGroup vGroup, VPath vPath, float stackedAlpha, @@ -745,47 +819,48 @@ public class VectorDrawable extends Drawable { vPath.toPath(mPath); final Path path = mPath; - if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) { - float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f; - float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f; - - if (mPathMeasure == null) { - mPathMeasure = new PathMeasure(); - } - mPathMeasure.setPath(mPath, false); - - float len = mPathMeasure.getLength(); - start = start * len; - end = end * len; - path.reset(); - if (start > end) { - mPathMeasure.getSegment(start, len, path, true); - mPathMeasure.getSegment(0f, end, path, true); - } else { - mPathMeasure.getSegment(start, end, path, true); - } - path.rLineTo(0, 0); // fix bug in measure - } - mRenderPath.reset(); - mRenderPath.addPath(path, mFinalPathMatrix); - - if (vPath.mClip) { + if (vPath.isClipPath()) { + mRenderPath.addPath(path, mFinalPathMatrix); canvas.clipPath(mRenderPath, Region.Op.REPLACE); } else { - if (vPath.mFillColor != 0) { + VFullPath fullPath = (VFullPath) vPath; + if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) { + float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f; + float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f; + + if (mPathMeasure == null) { + mPathMeasure = new PathMeasure(); + } + mPathMeasure.setPath(mPath, false); + + float len = mPathMeasure.getLength(); + start = start * len; + end = end * len; + path.reset(); + if (start > end) { + mPathMeasure.getSegment(start, len, path, true); + mPathMeasure.getSegment(0f, end, path, true); + } else { + mPathMeasure.getSegment(start, end, path, true); + } + path.rLineTo(0, 0); // fix bug in measure + } + mRenderPath.addPath(path, mFinalPathMatrix); + + if (fullPath.mFillColor != 0) { if (mFillPaint == null) { mFillPaint = new Paint(); mFillPaint.setColorFilter(mColorFilter); mFillPaint.setStyle(Paint.Style.FILL); mFillPaint.setAntiAlias(true); } - mFillPaint.setColor(applyAlpha(vPath.mFillColor, stackedAlpha)); + mFillPaint.setColor(applyAlpha(fullPath.mFillColor, stackedAlpha)); canvas.drawPath(mRenderPath, mFillPaint); } - if (vPath.mStrokeColor != 0) { + if (fullPath.mStrokeColor != 0) { if (mStrokePaint == null) { mStrokePaint = new Paint(); mStrokePaint.setColorFilter(mColorFilter); @@ -794,70 +869,25 @@ public class VectorDrawable extends Drawable { } final Paint strokePaint = mStrokePaint; - if (vPath.mStrokeLineJoin != null) { - strokePaint.setStrokeJoin(vPath.mStrokeLineJoin); + if (fullPath.mStrokeLineJoin != null) { + strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin); } - if (vPath.mStrokeLineCap != null) { - strokePaint.setStrokeCap(vPath.mStrokeLineCap); + if (fullPath.mStrokeLineCap != null) { + strokePaint.setStrokeCap(fullPath.mStrokeLineCap); } - strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * minScale); + strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit * minScale); - strokePaint.setColor(applyAlpha(vPath.mStrokeColor, stackedAlpha)); - strokePaint.setStrokeWidth(vPath.mStrokeWidth * minScale); + strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, stackedAlpha)); + strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale); canvas.drawPath(mRenderPath, strokePaint); } } } - - private void parseViewport(Resources r, AttributeSet attrs) - throws XmlPullParserException { - final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport); - - // Account for any configuration changes. - mChangingConfigurations |= a.getChangingConfigurations(); - - mViewportWidth = a.getFloat( - R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth); - mViewportHeight = a.getFloat( - R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight); - - if (mViewportWidth <= 0) { - throw new XmlPullParserException(a.getPositionDescription() + - "<viewport> tag requires viewportWidth > 0"); - } else if (mViewportHeight <= 0) { - throw new XmlPullParserException(a.getPositionDescription() + - "<viewport> tag requires viewportHeight > 0"); - } - - a.recycle(); - } - - private void parseSize(Resources r, AttributeSet attrs) - throws XmlPullParserException { - final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize); - - // Account for any configuration changes. - mChangingConfigurations |= a.getChangingConfigurations(); - - mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth); - mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight); - - if (mBaseWidth <= 0) { - throw new XmlPullParserException(a.getPositionDescription() + - "<size> tag requires width > 0"); - } else if (mBaseHeight <= 0) { - throw new XmlPullParserException(a.getPositionDescription() + - "<size> tag requires height > 0"); - } - - a.recycle(); - } - } - static class VGroup { + private static class VGroup { // mStackedMatrix is only used temporarily when drawing, it combines all // the parents' local matrices with the current one. private final Matrix mStackedMatrix = new Matrix(); @@ -906,9 +936,15 @@ public class VectorDrawable extends Drawable { if (copyChild instanceof VGroup) { VGroup copyGroup = (VGroup) copyChild; mChildren.add(new VGroup(copyGroup, targetsMap)); - } else if (copyChild instanceof VPath) { - VPath copyPath = (VPath) copyChild; - VPath newPath = new VPath(copyPath); + } else { + VPath newPath = null; + if (copyChild instanceof VFullPath) { + newPath = new VFullPath((VFullPath) copyChild); + } else if (copyChild instanceof VClipPath) { + newPath = new VClipPath((VClipPath) copyChild); + } else { + throw new IllegalStateException("Unknown object in the tree!"); + } mChildren.add(newPath); if (newPath.mPathName != null) { targetsMap.put(newPath.mPathName, newPath); @@ -920,11 +956,77 @@ public class VectorDrawable extends Drawable { public VGroup() { } - /* Getter and Setter */ + public String getGroupName() { + return mGroupName; + } + + public Matrix getLocalMatrix() { + return mLocalMatrix; + } + + public boolean canApplyTheme() { + return mThemeAttrs != null; + } + + public void inflate(Resources res, AttributeSet attrs, Theme theme) { + final TypedArray a = obtainAttributes(res, theme, attrs, + R.styleable.VectorDrawableGroup); + updateStateFromTypedArray(a); + a.recycle(); + } + + private void updateStateFromTypedArray(TypedArray a) { + // Account for any configuration changes. + mChangingConfigurations |= a.getChangingConfigurations(); + + // Extract the theme attributes, if any. + mThemeAttrs = a.extractThemeAttrs(); + + mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); + mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); + mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); + mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX); + mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY); + mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX); + mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY); + mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha); + + final String groupName = a.getString(R.styleable.VectorDrawableGroup_name); + if (groupName != null) { + mGroupName = groupName; + } + + updateLocalMatrix(); + } + + public void applyTheme(Theme t) { + if (mThemeAttrs == null) { + return; + } + + final TypedArray a = t.resolveAttributes(mThemeAttrs, + R.styleable.VectorDrawableGroup); + updateStateFromTypedArray(a); + a.recycle(); + } + + private void updateLocalMatrix() { + // The order we apply is the same as the + // RenderNode.cpp::applyViewPropertyTransforms(). + mLocalMatrix.reset(); + mLocalMatrix.postTranslate(-mPivotX, -mPivotY); + mLocalMatrix.postScale(mScaleX, mScaleY); + mLocalMatrix.postRotate(mRotate, 0, 0); + mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY); + } + + /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ + @SuppressWarnings("unused") public float getRotation() { return mRotate; } + @SuppressWarnings("unused") public void setRotation(float rotation) { if (rotation != mRotate) { mRotate = rotation; @@ -932,10 +1034,12 @@ public class VectorDrawable extends Drawable { } } + @SuppressWarnings("unused") public float getPivotX() { return mPivotX; } + @SuppressWarnings("unused") public void setPivotX(float pivotX) { if (pivotX != mPivotX) { mPivotX = pivotX; @@ -943,10 +1047,12 @@ public class VectorDrawable extends Drawable { } } + @SuppressWarnings("unused") public float getPivotY() { return mPivotY; } + @SuppressWarnings("unused") public void setPivotY(float pivotY) { if (pivotY != mPivotY) { mPivotY = pivotY; @@ -954,10 +1060,12 @@ public class VectorDrawable extends Drawable { } } + @SuppressWarnings("unused") public float getScaleX() { return mScaleX; } + @SuppressWarnings("unused") public void setScaleX(float scaleX) { if (scaleX != mScaleX) { mScaleX = scaleX; @@ -965,10 +1073,12 @@ public class VectorDrawable extends Drawable { } } + @SuppressWarnings("unused") public float getScaleY() { return mScaleY; } + @SuppressWarnings("unused") public void setScaleY(float scaleY) { if (scaleY != mScaleY) { mScaleY = scaleY; @@ -976,10 +1086,12 @@ public class VectorDrawable extends Drawable { } } + @SuppressWarnings("unused") public float getTranslateX() { return mTranslateX; } + @SuppressWarnings("unused") public void setTranslateX(float translateX) { if (translateX != mTranslateX) { mTranslateX = translateX; @@ -987,10 +1099,12 @@ public class VectorDrawable extends Drawable { } } + @SuppressWarnings("unused") public float getTranslateY() { return mTranslateY; } + @SuppressWarnings("unused") public void setTranslateY(float translateY) { if (translateY != mTranslateY) { mTranslateY = translateY; @@ -998,81 +1112,114 @@ public class VectorDrawable extends Drawable { } } + @SuppressWarnings("unused") public float getAlpha() { return mGroupAlpha; } + @SuppressWarnings("unused") public void setAlpha(float groupAlpha) { if (groupAlpha != mGroupAlpha) { mGroupAlpha = groupAlpha; } } + } - public String getGroupName() { - return mGroupName; + /** + * Common Path information for clip path and normal path. + */ + private static class VPath { + protected PathParser.PathDataNode[] mNodes = null; + String mPathName; + int mChangingConfigurations; + + public VPath() { + // Empty constructor. } - public Matrix getLocalMatrix() { - return mLocalMatrix; + public VPath(VPath copy) { + mPathName = copy.mPathName; + mChangingConfigurations = copy.mChangingConfigurations; + mNodes = PathParser.deepCopyNodes(copy.mNodes); } - public boolean canApplyTheme() { - return mThemeAttrs != null; + public void toPath(Path path) { + path.reset(); + if (mNodes != null) { + PathParser.PathDataNode.nodesToPath(mNodes, path); + } } - public void inflate(Resources res, AttributeSet attrs, Theme theme) { - final TypedArray a = obtainAttributes(res, theme, attrs, - R.styleable.VectorDrawableGroup); - updateStateFromTypedArray(a); - a.recycle(); + public String getPathName() { + return mPathName; } - private void updateStateFromTypedArray(TypedArray a) { - // Account for any configuration changes. - mChangingConfigurations |= a.getChangingConfigurations(); + public boolean canApplyTheme() { + return false; + } - // Extract the theme attributes, if any. - mThemeAttrs = a.extractThemeAttrs(); + public void applyTheme(Theme t) { + } - mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); - mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); - mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); - mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX); - mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY); - mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX); - mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY); - mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha); + public boolean isClipPath() { + return false; + } - final String groupName = a.getString(R.styleable.VectorDrawableGroup_name); - if (groupName != null) { - mGroupName = groupName; + /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ + @SuppressWarnings("unused") + public PathParser.PathDataNode[] getPathData() { + return mNodes; + } + + @SuppressWarnings("unused") + public void setPathData(PathParser.PathDataNode[] nodes) { + if (!PathParser.canMorph(mNodes, nodes)) { + // This should not happen in the middle of animation. + mNodes = PathParser.deepCopyNodes(nodes); + } else { + PathParser.updateNodes(mNodes, nodes); } + } + } - updateLocalMatrix(); + /** + * Clip path, which only has name and pathData. + */ + private static class VClipPath extends VPath{ + public VClipPath() { + // Empty constructor. } - public void applyTheme(Theme t) { - if (mThemeAttrs == null) { - return; - } + public VClipPath(VClipPath copy) { + super(copy); + } - final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath); + public void inflate(Resources r, AttributeSet attrs, Theme theme) { + final TypedArray a = obtainAttributes(r, theme, attrs, + R.styleable.VectorDrawableClipPath); updateStateFromTypedArray(a); a.recycle(); } - private void updateLocalMatrix() { - // The order we apply is the same as the - // RenderNode.cpp::applyViewPropertyTransforms(). - mLocalMatrix.reset(); - mLocalMatrix.postTranslate(-mPivotX, -mPivotY); - mLocalMatrix.postScale(mScaleX, mScaleY); - mLocalMatrix.postRotate(mRotate, 0, 0); - mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY); + private void updateStateFromTypedArray(TypedArray a) { + // Account for any configuration changes. + mChangingConfigurations |= a.getChangingConfigurations(); + + mPathName = a.getString(R.styleable.VectorDrawableClipPath_name); + mNodes = PathParser.createNodesFromPathData(a.getString( + R.styleable.VectorDrawableClipPath_pathData)); + } + + @Override + public boolean isClipPath() { + return true; } } - private static class VPath { + /** + * Normal path, which contains all the fill / paint information. + */ + private static class VFullPath extends VPath { ///////////////////////////////////////////////////// // Variables below need to be copied (deep copy if applicable) for mutation. private int[] mThemeAttrs; @@ -1087,20 +1234,16 @@ public class VectorDrawable extends Drawable { float mTrimPathEnd = 1; float mTrimPathOffset = 0; - boolean mClip = false; Paint.Cap mStrokeLineCap = Paint.Cap.BUTT; Paint.Join mStrokeLineJoin = Paint.Join.MITER; float mStrokeMiterlimit = 4; - private PathParser.PathDataNode[] mNodes = null; - String mPathName; - private int mChangingConfigurations; - - public VPath() { + public VFullPath() { // Empty constructor. } - public VPath(VPath copy) { + public VFullPath(VFullPath copy) { + super(copy); mThemeAttrs = copy.mThemeAttrs; mStrokeColor = copy.mStrokeColor; @@ -1113,25 +1256,9 @@ public class VectorDrawable extends Drawable { mTrimPathEnd = copy.mTrimPathEnd; mTrimPathOffset = copy.mTrimPathOffset; - mClip = copy.mClip; mStrokeLineCap = copy.mStrokeLineCap; mStrokeLineJoin = copy.mStrokeLineJoin; mStrokeMiterlimit = copy.mStrokeMiterlimit; - - mNodes = PathParser.deepCopyNodes(copy.mNodes); - mPathName = copy.mPathName; - mChangingConfigurations = copy.mChangingConfigurations; - } - - public void toPath(Path path) { - path.reset(); - if (mNodes != null) { - PathParser.PathDataNode.nodesToPath(mNodes, path); - } - } - - public String getPathName() { - return mPathName; } private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) { @@ -1160,22 +1287,78 @@ public class VectorDrawable extends Drawable { } } - /* Setters and Getters, mostly used by animator from AnimatedVectorDrawable. */ - @SuppressWarnings("unused") - public PathParser.PathDataNode[] getPathData() { - return mNodes; + @Override + public boolean canApplyTheme() { + return mThemeAttrs != null; } - @SuppressWarnings("unused") - public void setPathData(PathParser.PathDataNode[] nodes) { - if (!PathParser.canMorph(mNodes, nodes)) { - // This should not happen in the middle of animation. - mNodes = PathParser.deepCopyNodes(nodes); - } else { - PathParser.updateNodes(mNodes, nodes); + public void inflate(Resources r, AttributeSet attrs, Theme theme) { + final TypedArray a = obtainAttributes(r, theme, attrs, + R.styleable.VectorDrawablePath); + updateStateFromTypedArray(a); + a.recycle(); + } + + private void updateStateFromTypedArray(TypedArray a) { + // Account for any configuration changes. + mChangingConfigurations |= a.getChangingConfigurations(); + + // Extract the theme attributes, if any. + mThemeAttrs = a.extractThemeAttrs(); + + mPathName = a.getString(R.styleable.VectorDrawablePath_name); + mNodes = PathParser.createNodesFromPathData(a.getString( + R.styleable.VectorDrawablePath_pathData)); + + mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor, + mFillColor); + mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, + mFillOpacity); + mStrokeLineCap = getStrokeLineCap(a.getInt( + R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); + mStrokeLineJoin = getStrokeLineJoin(a.getInt( + R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); + mStrokeMiterlimit = a.getFloat( + R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); + mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor, + mStrokeColor); + mStrokeOpacity = a.getFloat(R.styleable.VectorDrawablePath_strokeOpacity, + mStrokeOpacity); + mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, + mStrokeWidth); + mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, + mTrimPathEnd); + mTrimPathOffset = a.getFloat( + R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); + mTrimPathStart = a.getFloat( + R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); + + updateColorAlphas(); + } + + @Override + public void applyTheme(Theme t) { + if (mThemeAttrs == null) { + return; + } + + final TypedArray a = t.resolveAttributes(mThemeAttrs, + R.styleable.VectorDrawablePath); + updateStateFromTypedArray(a); + a.recycle(); + } + + private void updateColorAlphas() { + if (!Float.isNaN(mFillOpacity)) { + mFillColor = applyAlpha(mFillColor, mFillOpacity); + } + + if (!Float.isNaN(mStrokeOpacity)) { + mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity); } } + /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ @SuppressWarnings("unused") int getStroke() { return mStrokeColor; @@ -1255,69 +1438,5 @@ public class VectorDrawable extends Drawable { void setTrimPathOffset(float trimPathOffset) { mTrimPathOffset = trimPathOffset; } - - public boolean canApplyTheme() { - return mThemeAttrs != null; - } - - public void inflate(Resources r, AttributeSet attrs, Theme theme) { - final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath); - updateStateFromTypedArray(a); - a.recycle(); - } - - private void updateStateFromTypedArray(TypedArray a) { - // Account for any configuration changes. - mChangingConfigurations |= a.getChangingConfigurations(); - - // Extract the theme attributes, if any. - mThemeAttrs = a.extractThemeAttrs(); - - mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); - - mPathName = a.getString(R.styleable.VectorDrawablePath_name); - mNodes = PathParser.createNodesFromPathData(a.getString( - R.styleable.VectorDrawablePath_pathData)); - - mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); - mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); - mStrokeLineCap = getStrokeLineCap(a.getInt( - R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); - mStrokeLineJoin = getStrokeLineJoin(a.getInt( - R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); - mStrokeMiterlimit = a.getFloat( - R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); - mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); - mStrokeOpacity = a.getFloat( - R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); - mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); - mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); - mTrimPathOffset = a.getFloat( - R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); - mTrimPathStart = a.getFloat( - R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); - - updateColorAlphas(); - } - - public void applyTheme(Theme t) { - if (mThemeAttrs == null) { - return; - } - - final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath); - updateStateFromTypedArray(a); - a.recycle(); - } - - private void updateColorAlphas() { - if (!Float.isNaN(mFillOpacity)) { - mFillColor = applyAlpha(mFillColor, mFillOpacity); - } - - if (!Float.isNaN(mStrokeOpacity)) { - mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity); - } - } } } diff --git a/include/private/graphics/Canvas.h b/include/private/graphics/Canvas.h new file mode 100644 index 000000000000..3cd57f4d1110 --- /dev/null +++ b/include/private/graphics/Canvas.h @@ -0,0 +1,143 @@ +/* + * 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. + */ + +#ifndef ANDROID_GRAPHICS_CANVAS_H +#define ANDROID_GRAPHICS_CANVAS_H + +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkMatrix.h" + +namespace android { + +class Canvas { +public: + virtual ~Canvas() {}; + + static Canvas* create_canvas(SkBitmap* bitmap); + static Canvas* create_canvas(SkCanvas* skiaCanvas); + + // TODO: enable HWUI to either create similar canvas wrapper or subclass + // directly from Canvas + //static Canvas* create_canvas(uirenderer::Renderer* renderer); + + // TODO: this is a temporary affordance until all necessary logic can be + // moved within this interface! Further, the return value should + // NOT be unref'd and is valid until this canvas is destroyed or a + // new bitmap is set. + virtual SkCanvas* getSkCanvas() = 0; + + virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0; + + virtual bool isOpaque() = 0; + virtual int width() = 0; + virtual int height() = 0; + +// ---------------------------------------------------------------------------- +// Canvas state operations +// ---------------------------------------------------------------------------- + // Save (layer) + virtual int getSaveCount() const = 0; + virtual int save(SkCanvas::SaveFlags flags) = 0; + virtual void restore() = 0; + virtual void restoreToCount(int saveCount) = 0; + + virtual int saveLayer(float left, float top, float right, float bottom, + const SkPaint* paint, SkCanvas::SaveFlags flags) = 0; + virtual int saveLayerAlpha(float left, float top, float right, float bottom, + int alpha, SkCanvas::SaveFlags flags) = 0; + + // Matrix + virtual void getMatrix(SkMatrix* outMatrix) const = 0; + virtual void setMatrix(const SkMatrix& matrix) = 0; + + virtual void concat(const SkMatrix& matrix) = 0; + virtual void rotate(float degrees) = 0; + virtual void scale(float sx, float sy) = 0; + virtual void skew(float sx, float sy) = 0; + virtual void translate(float dx, float dy) = 0; + + // clip + virtual bool getClipBounds(SkRect* outRect) const = 0; + virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0; + virtual bool quickRejectPath(const SkPath& path) const = 0; + + virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0; + virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0; + virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0; + + // filters + virtual SkDrawFilter* getDrawFilter() = 0; + virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0; + +// ---------------------------------------------------------------------------- +// Canvas draw operations +// ---------------------------------------------------------------------------- + virtual void drawColor(int color, SkXfermode::Mode mode) = 0; + virtual void drawPaint(const SkPaint& paint) = 0; + + // Geometry + virtual void drawPoint(float x, float y, const SkPaint& paint) = 0; + virtual void drawPoints(const float* points, int count, const SkPaint& paint) = 0; + virtual void drawLine(float startX, float startY, float stopX, float stopY, + const SkPaint& paint) = 0; + virtual void drawLines(const float* points, int count, const SkPaint& paint) = 0; + virtual void drawRect(float left, float top, float right, float bottom, + const SkPaint& paint) = 0; + virtual void drawRoundRect(float left, float top, float right, float bottom, + float rx, float ry, const SkPaint& paint) = 0; + virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0; + virtual void drawOval(float left, float top, float right, float bottom, + const SkPaint& paint) = 0; + virtual void drawArc(float left, float top, float right, float bottom, + float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0; + virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0; + virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, + const float* verts, const float* tex, const int* colors, + const uint16_t* indices, int indexCount, const SkPaint& paint) = 0; + + // Bitmap-based + virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, + const SkPaint* paint) = 0; + virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, + const SkPaint* paint) = 0; + virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint) = 0; + virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, + const float* vertices, const int* colors, const SkPaint* paint) = 0; + + // Text + virtual void drawText(const uint16_t* text, const float* positions, int count, + const SkPaint& paint, float x, float y, + float boundsLeft, float boundsTop, float boundsRight, float boundsBottom) = 0; + virtual void drawPosText(const uint16_t* text, const float* positions, int count, + int posCount, const SkPaint& paint) = 0; + virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, + float hOffset, float vOffset, const SkPaint& paint) = 0; + + /* + * Specifies if the positions passed to ::drawText are absolute or relative + * to the (x,y) value provided. + * + * If true the (x,y) values are ignored. Otherwise, those (x,y) values need + * to be added to each glyph's position to get its absolute position. + */ + virtual bool drawTextAbsolutePos() const = 0; +}; + +}; // namespace android +#endif // ANDROID_GRAPHICS_CANVAS_H diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp index b9d7b12c115d..181230ad7547 100644 --- a/libs/hwui/AmbientShadow.cpp +++ b/libs/hwui/AmbientShadow.cpp @@ -48,7 +48,6 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque, const Vector3* vertices, int vertexCount, const Vector3& centroid3d, float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) { const int rays = SHADOW_RAY_COUNT; - VertexBuffer::Mode mode = VertexBuffer::kOnePolyRingShadow; // Validate the inputs. if (vertexCount < 3 || heightFactor <= 0 || rays <= 0 || geomFactor <= 0) { @@ -98,9 +97,9 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque, // calculate the normal N, which should be perpendicular to the edge of the // polygon (represented by the neighbor intersection points) . // Shadow's vertices will be generated as : P + N * scale. - const Vector2 centroid2d = Vector2(centroid3d.x, centroid3d.y); + const Vector2 centroid2d = {centroid3d.x, centroid3d.y}; for (int rayIndex = 0; rayIndex < rays; rayIndex++) { - Vector2 normal(1.0f, 0.0f); + Vector2 normal = {1.0f, 0.0f}; calculateNormal(rays, rayIndex, dir.array(), rayDist, normal); // The vertex should be start from rayDist[i] then scale the @@ -124,19 +123,23 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque, opacity); } - // If caster isn't opaque, we need to to fill the umbra by storing the umbra's - // centroid in the innermost ring of vertices. - if (!isCasterOpaque) { - mode = VertexBuffer::kTwoPolyRingShadow; + if (isCasterOpaque) { + // skip inner ring, calc bounds over filled portion of buffer + shadowVertexBuffer.computeBounds<AlphaVertex>(2 * rays); + shadowVertexBuffer.setMode(VertexBuffer::kOnePolyRingShadow); + } else { + // If caster isn't opaque, we need to to fill the umbra by storing the umbra's + // centroid in the innermost ring of vertices. float centroidAlpha = 1.0 / (1 + centroid3d.z * heightFactor); AlphaVertex centroidXYA; AlphaVertex::set(¢roidXYA, centroid2d.x, centroid2d.y, centroidAlpha); for (int rayIndex = 0; rayIndex < rays; rayIndex++) { shadowVertices[2 * rays + rayIndex] = centroidXYA; } + // calc bounds over entire buffer + shadowVertexBuffer.computeBounds<AlphaVertex>(); + shadowVertexBuffer.setMode(VertexBuffer::kTwoPolyRingShadow); } - shadowVertexBuffer.setMode(mode); - shadowVertexBuffer.computeBounds<AlphaVertex>(); #if DEBUG_SHADOW for (int i = 0; i < SHADOW_VERTEX_COUNT; i++) { diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index 9202e49cea9d..bf7828c3c175 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -49,7 +49,7 @@ public: LayerRenderer(RenderState& renderState, Layer* layer); virtual ~LayerRenderer(); - virtual void onViewportInitialized(int width, int height) { /* do nothing */ } + virtual void onViewportInitialized() { /* do nothing */ } virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); virtual status_t clear(float left, float top, float right, float bottom, bool opaque); virtual void finish(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 5a96132217a6..41f89c254c14 100755 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -132,19 +132,21 @@ static inline T min(T a, T b) { /////////////////////////////////////////////////////////////////////////////// OpenGLRenderer::OpenGLRenderer(RenderState& renderState) - : mCaches(Caches::getInstance()) + : mFrameStarted(false) + , mCaches(Caches::getInstance()) , mExtensions(Extensions::getInstance()) - , mRenderState(renderState) { + , mRenderState(renderState) + , mScissorOptimizationDisabled(false) + , mCountOverdraw(false) + , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN}) + , mLightRadius(FLT_MIN) + , mAmbientShadowAlpha(0) + , mSpotShadowAlpha(0) { // *set* draw modifiers to be 0 memset(&mDrawModifiers, 0, sizeof(mDrawModifiers)); mDrawModifiers.mOverrideLayerAlpha = 1.0f; memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); - - mFrameStarted = false; - mCountOverdraw = false; - - mScissorOptimizationDisabled = false; } OpenGLRenderer::~OpenGLRenderer() { @@ -163,6 +165,14 @@ void OpenGLRenderer::initProperties() { } } +void OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius, + uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { + mLightCenter = lightCenter; + mLightRadius = lightRadius; + mAmbientShadowAlpha = ambientShadowAlpha; + mSpotShadowAlpha = spotShadowAlpha; +} + /////////////////////////////////////////////////////////////////////////////// // Setup /////////////////////////////////////////////////////////////////////////////// @@ -1924,7 +1934,9 @@ status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int return deferredList.flush(*this, dirty) | status; } - return DrawGlInfo::kStatusDone; + // Even if there is no drawing command(Ex: invisible), + // it still needs startFrame to clear buffer and start tiling. + return startFrame(); } void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) { @@ -3172,13 +3184,13 @@ status_t OpenGLRenderer::drawShadow(float casterAlpha, SkPaint paint; paint.setAntiAlias(true); // want to use AlphaVertex - if (ambientShadowVertexBuffer && mCaches.propertyAmbientShadowStrength > 0) { - paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0); + if (ambientShadowVertexBuffer && mAmbientShadowAlpha > 0) { + paint.setARGB(casterAlpha * mAmbientShadowAlpha, 0, 0, 0); drawVertexBuffer(*ambientShadowVertexBuffer, &paint); } - if (spotShadowVertexBuffer && mCaches.propertySpotShadowStrength > 0) { - paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0); + if (spotShadowVertexBuffer && mSpotShadowAlpha > 0) { + paint.setARGB(casterAlpha * mSpotShadowAlpha, 0, 0, 0); drawVertexBuffer(*spotShadowVertexBuffer, &paint); } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 4e7844bb0bdc..f698b457ebd8 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -124,6 +124,8 @@ public: virtual ~OpenGLRenderer(); void initProperties(); + void initLight(const Vector3& lightCenter, float lightRadius, + uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); virtual void onViewportInitialized(); virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); @@ -1010,6 +1012,12 @@ private: bool mSkipOutlineClip; + // Lighting + shadows + Vector3 mLightCenter; + float mLightRadius; + uint8_t mAmbientShadowAlpha; + uint8_t mSpotShadowAlpha; + friend class Layer; friend class TextSetupFunctor; friend class DrawBitmapOp; diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp index 804ec418117c..209341ccb503 100644 --- a/libs/hwui/PathTessellator.cpp +++ b/libs/hwui/PathTessellator.cpp @@ -90,7 +90,7 @@ void PathTessellator::extractTessellationScales(const Matrix4& transform, * * NOTE: assumes angles between normals 90 degrees or less */ -inline static vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { +inline static Vector2 totalOffsetFromNormals(const Vector2& normalA, const Vector2& normalB) { return (normalA + normalB) / (1 + fabs(normalA.dot(normalB))); } @@ -129,7 +129,7 @@ public: float halfStrokeWidth; float maxAlpha; - inline void scaleOffsetForStrokeWidth(vec2& offset) const { + inline void scaleOffsetForStrokeWidth(Vector2& offset) const { if (halfStrokeWidth == 0.0f) { // hairline - compensate for scale offset.x *= 0.5f * inverseScaleX; @@ -143,9 +143,8 @@ public: * NOTE: the input will not always be a normal, especially for sharp edges - it should be the * result of totalOffsetFromNormals (see documentation there) */ - inline vec2 deriveAAOffset(const vec2& offset) const { - return vec2(offset.x * 0.5f * inverseScaleX, - offset.y * 0.5f * inverseScaleY); + inline Vector2 deriveAAOffset(const Vector2& offset) const { + return (Vector2){offset.x * 0.5f * inverseScaleX, offset.y * 0.5f * inverseScaleY}; } /** @@ -208,16 +207,14 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo, const Vector<Ver int currentIndex = 0; const Vertex* last = &(perimeter[perimeter.size() - 1]); const Vertex* current = &(perimeter[0]); - vec2 lastNormal(current->y - last->y, - last->x - current->x); + Vector2 lastNormal = {current->y - last->y, last->x - current->x}; lastNormal.normalize(); for (unsigned int i = 0; i < perimeter.size(); i++) { const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]); - vec2 nextNormal(next->y - current->y, - current->x - next->x); + Vector2 nextNormal = {next->y - current->y, current->x - next->x}; nextNormal.normalize(); - vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); + Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); paintInfo.scaleOffsetForStrokeWidth(totalOffset); Vertex::set(&buffer[currentIndex++], @@ -241,13 +238,14 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo, const Vector<Ver } static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center, - const vec2& normal, Vertex* buffer, int& currentIndex, bool begin) { - vec2 strokeOffset = normal; + const Vector2& normal, Vertex* buffer, int& currentIndex, bool begin) { + Vector2 strokeOffset = normal; paintInfo.scaleOffsetForStrokeWidth(strokeOffset); - vec2 referencePoint(center.x, center.y); + Vector2 referencePoint = {center.x, center.y}; if (paintInfo.cap == SkPaint::kSquare_Cap) { - referencePoint += vec2(-strokeOffset.y, strokeOffset.x) * (begin ? -1 : 1); + Vector2 rotated = {-strokeOffset.y, strokeOffset.x}; + referencePoint += rotated * (begin ? -1 : 1); } Vertex::set(&buffer[currentIndex++], referencePoint + strokeOffset); @@ -288,14 +286,14 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo, } beginTheta += dTheta; - vec2 beginRadialOffset(cos(beginTheta), sin(beginTheta)); + Vector2 beginRadialOffset = {cos(beginTheta), sin(beginTheta)}; paintInfo.scaleOffsetForStrokeWidth(beginRadialOffset); Vertex::set(&buffer[capOffset], vertices[0].x + beginRadialOffset.x, vertices[0].y + beginRadialOffset.y); endTheta += dTheta; - vec2 endRadialOffset(cos(endTheta), sin(endTheta)); + Vector2 endRadialOffset = {cos(endTheta), sin(endTheta)}; paintInfo.scaleOffsetForStrokeWidth(endRadialOffset); Vertex::set(&buffer[allocSize - 1 - capOffset], vertices[lastIndex].x + endRadialOffset.x, @@ -306,22 +304,20 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo, int currentIndex = extra; const Vertex* last = &(vertices[0]); const Vertex* current = &(vertices[1]); - vec2 lastNormal(current->y - last->y, - last->x - current->x); + Vector2 lastNormal = {current->y - last->y, last->x - current->x}; lastNormal.normalize(); storeBeginEnd(paintInfo, vertices[0], lastNormal, buffer, currentIndex, true); for (unsigned int i = 1; i < vertices.size() - 1; i++) { const Vertex* next = &(vertices[i + 1]); - vec2 nextNormal(next->y - current->y, - current->x - next->x); + Vector2 nextNormal = {next->y - current->y, current->x - next->x}; nextNormal.normalize(); - vec2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal); + Vector2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal); paintInfo.scaleOffsetForStrokeWidth(strokeOffset); - vec2 center(current->x, current->y); + Vector2 center = {current->x, current->y}; Vertex::set(&buffer[currentIndex++], center + strokeOffset); Vertex::set(&buffer[currentIndex++], center - strokeOffset); @@ -353,18 +349,16 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<Ver int currentIndex = 0; const Vertex* last = &(perimeter[perimeter.size() - 1]); const Vertex* current = &(perimeter[0]); - vec2 lastNormal(current->y - last->y, - last->x - current->x); + Vector2 lastNormal = {current->y - last->y, last->x - current->x}; lastNormal.normalize(); for (unsigned int i = 0; i < perimeter.size(); i++) { const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]); - vec2 nextNormal(next->y - current->y, - current->x - next->x); + Vector2 nextNormal = {next->y - current->y, current->x - next->x}; nextNormal.normalize(); // AA point offset from original point is that point's normal, such that each side is offset // by .5 pixels - vec2 totalOffset = paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal)); + Vector2 totalOffset = paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal)); AlphaVertex::set(&buffer[currentIndex++], current->x + totalOffset.x, @@ -407,7 +401,7 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<Ver * getStrokeVerticesFromUnclosedVerticesAA() below. */ inline static void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices, - AlphaVertex* buffer, bool isFirst, vec2 normal, int offset) { + AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) { const int extra = paintInfo.capExtraDivisions(); const int extraOffset = (extra + 1) / 2; const int capIndex = isFirst @@ -416,27 +410,28 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& if (isFirst) normal *= -1; // TODO: this normal should be scaled by radialScale if extra != 0, see totalOffsetFromNormals() - vec2 AAOffset = paintInfo.deriveAAOffset(normal); + Vector2 AAOffset = paintInfo.deriveAAOffset(normal); - vec2 strokeOffset = normal; + Vector2 strokeOffset = normal; paintInfo.scaleOffsetForStrokeWidth(strokeOffset); - vec2 outerOffset = strokeOffset + AAOffset; - vec2 innerOffset = strokeOffset - AAOffset; + Vector2 outerOffset = strokeOffset + AAOffset; + Vector2 innerOffset = strokeOffset - AAOffset; - vec2 capAAOffset; + Vector2 capAAOffset = {0, 0}; if (paintInfo.cap != SkPaint::kRound_Cap) { // if the cap is square or butt, the inside primary cap vertices will be inset in two // directions - both normal to the stroke, and parallel to it. - capAAOffset = vec2(-AAOffset.y, AAOffset.x); + capAAOffset = (Vector2){-AAOffset.y, AAOffset.x}; } // determine referencePoint, the center point for the 4 primary cap vertices const Vertex* point = isFirst ? vertices.begin() : (vertices.end() - 1); - vec2 referencePoint(point->x, point->y); + Vector2 referencePoint = {point->x, point->y}; if (paintInfo.cap == SkPaint::kSquare_Cap) { // To account for square cap, move the primary cap vertices (that create the AA edge) by the // stroke offset vector (rotated to be parallel to the stroke) - referencePoint += vec2(-strokeOffset.y, strokeOffset.x); + Vector2 rotated = {-strokeOffset.y, strokeOffset.x}; + referencePoint += rotated; } AlphaVertex::set(&buffer[capIndex + 0], @@ -469,7 +464,7 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& for (int i = 0; i < extra; i++) { theta += dTheta; - vec2 radialOffset(cos(theta), sin(theta)); + Vector2 radialOffset = {cos(theta), sin(theta)}; // scale to compensate for pinching at sharp angles, see totalOffsetFromNormals() radialOffset *= radialScale; @@ -592,8 +587,7 @@ void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo, const Vertex* last = &(vertices[0]); const Vertex* current = &(vertices[1]); - vec2 lastNormal(current->y - last->y, - last->x - current->x); + Vector2 lastNormal = {current->y - last->y, last->x - current->x}; lastNormal.normalize(); // TODO: use normal from bezier traversal for cap, instead of from vertices @@ -601,16 +595,15 @@ void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo, for (unsigned int i = 1; i < vertices.size() - 1; i++) { const Vertex* next = &(vertices[i + 1]); - vec2 nextNormal(next->y - current->y, - current->x - next->x); + Vector2 nextNormal = {next->y - current->y, current->x - next->x}; nextNormal.normalize(); - vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); - vec2 AAOffset = paintInfo.deriveAAOffset(totalOffset); + Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); + Vector2 AAOffset = paintInfo.deriveAAOffset(totalOffset); - vec2 innerOffset = totalOffset; + Vector2 innerOffset = totalOffset; paintInfo.scaleOffsetForStrokeWidth(innerOffset); - vec2 outerOffset = innerOffset + AAOffset; + Vector2 outerOffset = innerOffset + AAOffset; innerOffset -= AAOffset; AlphaVertex::set(&buffer[currentAAOuterIndex++], @@ -662,21 +655,19 @@ void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<V const Vertex* last = &(perimeter[perimeter.size() - 1]); const Vertex* current = &(perimeter[0]); - vec2 lastNormal(current->y - last->y, - last->x - current->x); + Vector2 lastNormal = {current->y - last->y, last->x - current->x}; lastNormal.normalize(); for (unsigned int i = 0; i < perimeter.size(); i++) { const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]); - vec2 nextNormal(next->y - current->y, - current->x - next->x); + Vector2 nextNormal = {next->y - current->y, current->x - next->x}; nextNormal.normalize(); - vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); - vec2 AAOffset = paintInfo.deriveAAOffset(totalOffset); + Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); + Vector2 AAOffset = paintInfo.deriveAAOffset(totalOffset); - vec2 innerOffset = totalOffset; + Vector2 innerOffset = totalOffset; paintInfo.scaleOffsetForStrokeWidth(innerOffset); - vec2 outerOffset = innerOffset + AAOffset; + Vector2 outerOffset = innerOffset + AAOffset; innerOffset -= AAOffset; AlphaVertex::set(&buffer[currentAAOuterIndex++], diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 32304dc9f7d7..1df205584744 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -352,31 +352,35 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { } } const bool isLayer = properties().layerProperties().type() != kLayerTypeNone; - bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds(); + int clipFlags = properties().getClippingFlags(); if (properties().getAlpha() < 1) { if (isLayer) { + clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer + renderer.setOverrideLayerAlpha(properties().getAlpha()); } else if (!properties().getHasOverlappingRendering()) { renderer.scaleAlpha(properties().getAlpha()); } else { - // TODO: should be able to store the size of a DL at record time and not - // have to pass it into this call. In fact, this information might be in the - // location/size info that we store with the new native transform data. + Rect layerBounds(0, 0, getWidth(), getHeight()); int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag; - if (clipToBoundsNeeded) { + if (clipFlags) { saveFlags |= SkCanvas::kClipToLayer_SaveFlag; - clipToBoundsNeeded = false; // clipping done by saveLayer + properties().getClippingRectForFlags(clipFlags, &layerBounds); + clipFlags = 0; // all clipping done by saveLayer } SaveLayerOp* op = new (handler.allocator()) SaveLayerOp( - 0, 0, properties().getWidth(), properties().getHeight(), + layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom, properties().getAlpha() * 255, saveFlags); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } } - if (clipToBoundsNeeded) { + if (clipFlags) { + Rect clipRect; + properties().getClippingRectForFlags(clipFlags, &clipRect); ClipRectOp* op = new (handler.allocator()) ClipRectOp( - 0, 0, properties().getWidth(), properties().getHeight(), SkRegion::kIntersect_Op); + clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, + SkRegion::kIntersect_Op); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } @@ -841,7 +845,8 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); const int saveCountOffset = renderer.getSaveCount() - 1; const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex; - for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { + const int size = static_cast<int>(mDisplayListData->displayListOps.size()); + for (int i = 0; i < size; i++) { DisplayListOp *op = mDisplayListData->displayListOps[i]; #if DEBUG_DISPLAY_LIST diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp index 8848b2f76da7..250cadcfe51e 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -75,7 +75,7 @@ LayerProperties& LayerProperties::operator=(const LayerProperties& other) { } RenderProperties::PrimitiveFields::PrimitiveFields() - : mClipToBounds(true) + : mClippingFlags(CLIP_TO_BOUNDS) , mProjectBackwards(false) , mProjectionReceiver(false) , mAlpha(1) @@ -146,26 +146,34 @@ void RenderProperties::debugOutputProperties(const int level) const { } } - bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds; + const bool isLayer = layerProperties().type() != kLayerTypeNone; + int clipFlags = getClippingFlags(); if (mPrimitiveFields.mAlpha < 1) { - if (layerProperties().type() != kLayerTypeNone) { + if (isLayer) { + clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer + ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha); } else if (!mPrimitiveFields.mHasOverlappingRendering) { ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha); } else { - int flags = SkCanvas::kHasAlphaLayer_SaveFlag; - if (clipToBoundsNeeded) { - flags |= SkCanvas::kClipToLayer_SaveFlag; - clipToBoundsNeeded = false; // clipping done by save layer + Rect layerBounds(0, 0, getWidth(), getHeight()); + int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag; + if (clipFlags) { + saveFlags |= SkCanvas::kClipToLayer_SaveFlag; + getClippingRectForFlags(clipFlags, &layerBounds); + clipFlags = 0; // all clipping done by saveLayer } + ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "", - 0, 0, getWidth(), getHeight(), - (int)(mPrimitiveFields.mAlpha * 255), flags); + (int)layerBounds.left, (int)layerBounds.top, (int)layerBounds.right, (int)layerBounds.bottom, + (int)(mPrimitiveFields.mAlpha * 255), saveFlags); } } - if (clipToBoundsNeeded) { + if (clipFlags) { + Rect clipRect; + getClippingRectForFlags(clipFlags, &clipRect); ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "", - 0, 0, getWidth(), getHeight()); + (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom); } } diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 227d56eb3bd6..f50e514f5d5d 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -58,6 +58,11 @@ enum LayerType { // TODO: LayerTypeSurfaceTexture? Maybe? }; +enum ClippingFlags { + CLIP_TO_BOUNDS = 0x1 << 0, + CLIP_TO_CLIP_BOUNDS = 0x1 << 1, +}; + class ANDROID_API LayerProperties { public: bool setType(LayerType type) { @@ -135,10 +140,35 @@ public: RenderProperties(); virtual ~RenderProperties(); + static bool setFlag(int flag, bool newValue, int* outFlags) { + if (newValue) { + if (!(flag & *outFlags)) { + *outFlags |= flag; + return true; + } + return false; + } else { + if (flag & *outFlags) { + *outFlags &= ~flag; + return true; + } + return false; + } + } + RenderProperties& operator=(const RenderProperties& other); bool setClipToBounds(bool clipToBounds) { - return RP_SET(mPrimitiveFields.mClipToBounds, clipToBounds); + return setFlag(CLIP_TO_BOUNDS, clipToBounds, &mPrimitiveFields.mClippingFlags); + } + + bool setClipBounds(const Rect& clipBounds) { + bool ret = setFlag(CLIP_TO_CLIP_BOUNDS, true, &mPrimitiveFields.mClippingFlags); + return RP_SET(mPrimitiveFields.mClipBounds, clipBounds) || ret; + } + + bool setClipBoundsEmpty() { + return setFlag(CLIP_TO_CLIP_BOUNDS, false, &mPrimitiveFields.mClippingFlags); } bool setProjectBackwards(bool shouldProject) { @@ -433,7 +463,7 @@ public: return false; } - bool offsetLeftRight(float offset) { + bool offsetLeftRight(int offset) { if (offset != 0) { mPrimitiveFields.mLeft += offset; mPrimitiveFields.mRight += offset; @@ -442,7 +472,7 @@ public: return false; } - bool offsetTopBottom(float offset) { + bool offsetTopBottom(int offset) { if (offset != 0) { mPrimitiveFields.mTop += offset; mPrimitiveFields.mBottom += offset; @@ -477,8 +507,23 @@ public: return mComputedFields.mTransformMatrix; } + int getClippingFlags() const { + return mPrimitiveFields.mClippingFlags; + } + bool getClipToBounds() const { - return mPrimitiveFields.mClipToBounds; + return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS; + } + + void getClippingRectForFlags(uint32_t flags, Rect* outRect) const { + if (flags & CLIP_TO_BOUNDS) { + outRect->set(0, 0, getWidth(), getHeight()); + if (flags & CLIP_TO_CLIP_BOUNDS) { + outRect->intersect(mPrimitiveFields.mClipBounds); + } + } else { + outRect->set(mPrimitiveFields.mClipBounds); + } } bool getHasOverlappingRendering() const { @@ -540,14 +585,13 @@ public: } private: - // Rendering properties struct PrimitiveFields { PrimitiveFields(); Outline mOutline; RevealClip mRevealClip; - bool mClipToBounds; + int mClippingFlags; bool mProjectBackwards; bool mProjectionReceiver; float mAlpha; @@ -561,6 +605,7 @@ private: int mWidth, mHeight; bool mPivotExplicitlySet; bool mMatrixOrPivotDirty; + Rect mClipBounds; } mPrimitiveFields; SkMatrix* mStaticMatrix; diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index ccd3ba56efd0..40a21e4a5173 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -80,14 +80,6 @@ public: virtual void setViewport(int width, int height) = 0; /** - * Sets the position and size of the spot shadow casting light. - * - * @param lightCenter The light's Y position, relative to the render target's top left - * @param lightRadius The light's radius - */ - virtual void initializeLight(const Vector3& lightCenter, float lightRadius) = 0; - - /** * Prepares the renderer to draw a frame. This method must be invoked * at the beginning of each frame. When this method is invoked, the * entire drawing surface is assumed to be redrawn. diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp index bcfda99dfe26..e71439d844ce 100644 --- a/libs/hwui/ShadowTessellator.cpp +++ b/libs/hwui/ShadowTessellator.cpp @@ -172,7 +172,8 @@ Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) { Vector2 centroid = poly[0]; if (area != 0) { - centroid = Vector2(sumx / (3 * area), sumy / (3 * area)); + centroid = (Vector2){static_cast<float>(sumx / (3 * area)), + static_cast<float>(sumy / (3 * area))}; } else { ALOGW("Area is 0 while computing centroid!"); } @@ -212,19 +213,19 @@ bool ShadowTessellator::isClockwisePath(const SkPath& path) { while (SkPath::kDone_Verb != (v = iter.next(pts))) { switch (v) { case SkPath::kMove_Verb: - arrayForDirection.add(Vector2(pts[0].x(), pts[0].y())); + arrayForDirection.add((Vector2){pts[0].x(), pts[0].y()}); break; case SkPath::kLine_Verb: - arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); + arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()}); break; case SkPath::kQuad_Verb: - arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); - arrayForDirection.add(Vector2(pts[2].x(), pts[2].y())); + arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()}); + arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()}); break; case SkPath::kCubic_Verb: - arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); - arrayForDirection.add(Vector2(pts[2].x(), pts[2].y())); - arrayForDirection.add(Vector2(pts[3].x(), pts[3].y())); + arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()}); + arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()}); + arrayForDirection.add((Vector2){pts[3].x(), pts[3].y()}); break; default: break; diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp index 82dbe7a1485a..8c3077b682be 100644 --- a/libs/hwui/SpotShadow.cpp +++ b/libs/hwui/SpotShadow.cpp @@ -218,7 +218,7 @@ int SpotShadow::intersection(const Vector2* poly1, int poly1Length, // Since neither polygon fully contain the other one, we need to add all the // intersection points. - Vector2 intersection; + Vector2 intersection = {0, 0}; for (int i = 0; i < poly2Length; i++) { for (int j = 0; j < poly1Length; j++) { int poly2LineStart = i; @@ -250,7 +250,7 @@ int SpotShadow::intersection(const Vector2* poly1, int poly1Length, } // Sort the result polygon around the center. - Vector2 center(0.0f, 0.0f); + Vector2 center = {0.0f, 0.0f}; for (int i = 0; i < count; i++) { center += poly[i]; } @@ -507,8 +507,6 @@ void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3* poly, computeLightPolygon(lightVertexCount, lightCenter, lightSize, light); computeSpotShadow(isCasterOpaque, light, lightVertexCount, lightCenter, poly, polyLength, retStrips); - retStrips.setMode(VertexBuffer::kTwoPolyRingShadow); - retStrips.computeBounds<AlphaVertex>(); } /** @@ -559,7 +557,7 @@ void SpotShadow::computeSpotShadow(bool isCasterOpaque, const Vector3* lightPoly float x = lightPoly[j].x - ratioZ * (lightPoly[j].x - poly[i].x); float y = lightPoly[j].y - ratioZ * (lightPoly[j].y - poly[i].y); - Vector2 newPoint = Vector2(x, y); + Vector2 newPoint = {x, y}; shadowRegion[k] = newPoint; outline[m] = newPoint; @@ -785,6 +783,9 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, const Vector2* penum shadowVertices[2 * rays + rayIndex] = centroidXYA; } } + + shadowTriangleStrip.setMode(VertexBuffer::kTwoPolyRingShadow); + shadowTriangleStrip.computeBounds<AlphaVertex>(); } /** diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp index 95c0ee5745b9..140c6e82f538 100644 --- a/libs/hwui/StatefulBaseRenderer.cpp +++ b/libs/hwui/StatefulBaseRenderer.cpp @@ -23,10 +23,13 @@ namespace android { namespace uirenderer { -StatefulBaseRenderer::StatefulBaseRenderer() : - mDirtyClip(false), mWidth(-1), mHeight(-1), - mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot), - mLightCenter(FLT_MIN, FLT_MIN, FLT_MIN), mLightRadius(FLT_MIN) { +StatefulBaseRenderer::StatefulBaseRenderer() + : mDirtyClip(false) + , mWidth(-1) + , mHeight(-1) + , mSaveCount(1) + , mFirstSnapshot(new Snapshot) + , mSnapshot(mFirstSnapshot) { } void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop, @@ -45,11 +48,6 @@ void StatefulBaseRenderer::setViewport(int width, int height) { onViewportInitialized(); } -void StatefulBaseRenderer::initializeLight(const Vector3& lightCenter, float lightRadius) { - mLightCenter = lightCenter; - mLightRadius = lightRadius; -} - /////////////////////////////////////////////////////////////////////////////// // Save (layer) /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h index e8e024f342b0..25cc832e5b6f 100644 --- a/libs/hwui/StatefulBaseRenderer.h +++ b/libs/hwui/StatefulBaseRenderer.h @@ -52,7 +52,6 @@ public: * the render target. */ virtual void setViewport(int width, int height); - virtual void initializeLight(const Vector3& lightCenter, float lightRadius); void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom); // getters @@ -161,10 +160,6 @@ protected: // Current state // TODO: should become private, once hooks needed by OpenGLRenderer are added sp<Snapshot> mSnapshot; - - Vector3 mLightCenter; - float mLightRadius; - }; // class StatefulBaseRenderer }; // namespace uirenderer diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index 343f1aa9c127..c5fc21fcfa90 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -125,7 +125,7 @@ public: } }; -struct TessellationCache::Buffer { +class TessellationCache::Buffer { public: Buffer(const sp<Task<VertexBuffer*> >& task) : mTask(task) @@ -236,7 +236,7 @@ static void tessellateShadows( float maxZ = -FLT_MAX; for (int i = 0; i < casterVertexCount; i++) { const Vertex& point2d = casterVertices2d[i]; - casterPolygon[i] = Vector3(point2d.x, point2d.y, 0); + casterPolygon[i] = (Vector3){point2d.x, point2d.y, 0}; mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ); minZ = fmin(minZ, casterPolygon[i].z); maxZ = fmax(maxZ, casterPolygon[i].z); @@ -246,7 +246,7 @@ static void tessellateShadows( Vector2 centroid = ShadowTessellator::centroid2d( reinterpret_cast<const Vector2*>(casterVertices2d.array()), casterVertexCount); - Vector3 centroid3d(centroid.x, centroid.y, 0); + Vector3 centroid3d = {centroid.x, centroid.y, 0}; mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ); // if the caster intersects the z=0 plane, lift it in Z so it doesn't diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h index c61cb6183807..2a9f01ca06aa 100644 --- a/libs/hwui/Vector.h +++ b/libs/hwui/Vector.h @@ -24,18 +24,11 @@ namespace uirenderer { // Classes /////////////////////////////////////////////////////////////////////////////// +// MUST BE A POD - this means no ctor or dtor! struct Vector2 { float x; float y; - Vector2() : - x(0.0f), y(0.0f) { - } - - Vector2(float px, float py) : - x(px), y(py) { - } - float lengthSquared() const { return x * x + y * y; } @@ -75,19 +68,19 @@ struct Vector2 { } Vector2 operator+(const Vector2& v) const { - return Vector2(x + v.x, y + v.y); + return (Vector2){x + v.x, y + v.y}; } Vector2 operator-(const Vector2& v) const { - return Vector2(x - v.x, y - v.y); + return (Vector2){x - v.x, y - v.y}; } Vector2 operator/(float s) const { - return Vector2(x / s, y / s); + return (Vector2){x / s, y / s}; } Vector2 operator*(float s) const { - return Vector2(x * s, y * s); + return (Vector2){x * s, y * s}; } void normalize() { @@ -97,7 +90,7 @@ struct Vector2 { } Vector2 copyNormalized() const { - Vector2 v(x, y); + Vector2 v = {x, y}; v.normalize(); return v; } @@ -111,31 +104,18 @@ struct Vector2 { } }; // class Vector2 +// MUST BE A POD - this means no ctor or dtor! class Vector3 { public: float x; float y; float z; - Vector3() : - x(0.0f), y(0.0f), z(0.0f) { - } - - Vector3(float px, float py, float pz) : - x(px), y(py), z(pz) { - } - void dump() { ALOGD("Vector3[%.2f, %.2f, %.2f]", x, y, z); } }; -/////////////////////////////////////////////////////////////////////////////// -// Types -/////////////////////////////////////////////////////////////////////////////// - -typedef Vector2 vec2; - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h index 5d7a19921e35..4ff0b183cfb6 100644 --- a/libs/hwui/Vertex.h +++ b/libs/hwui/Vertex.h @@ -43,7 +43,7 @@ struct Vertex { vertex[0].y = y; } - static inline void set(Vertex* vertex, vec2 val) { + static inline void set(Vertex* vertex, Vector2 val) { set(vertex, val.x, val.y); } diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h index 5875f25aa514..3837f88e0153 100644 --- a/libs/hwui/VertexBuffer.h +++ b/libs/hwui/VertexBuffer.h @@ -62,7 +62,6 @@ public: mVertexCount = vertexCount; mByteCount = mVertexCount * sizeof(TYPE); mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount]; - memset(mBuffer, 0, sizeof(TYPE) * vertexCount); mCleanupMethod = &(cleanup<TYPE>); @@ -86,13 +85,17 @@ public: * vertex buffer can't determine bounds more simply/efficiently */ template <class TYPE> - void computeBounds() { + void computeBounds(int vertexCount = 0) { if (!mVertexCount) { mBounds.setEmpty(); return; } + + // default: compute over every vertex + if (vertexCount == 0) vertexCount = mVertexCount; + TYPE* current = (TYPE*)mBuffer; - TYPE* end = current + mVertexCount; + TYPE* end = current + vertexCount; mBounds.set(current->x, current->y, current->x, current->y); for (; current < end; current++) { mBounds.expandToCoverVertex(current->x, current->y); diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 214781095b5e..756f6606375d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -110,10 +110,11 @@ void CanvasContext::pauseSurface(ANativeWindow* window) { // and such to prevent from trying to render into this surface } -void CanvasContext::setup(int width, int height, const Vector3& lightCenter, float lightRadius) { +void CanvasContext::setup(int width, int height, const Vector3& lightCenter, float lightRadius, + uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { if (!mCanvas) return; mCanvas->setViewport(width, height); - mCanvas->initializeLight(lightCenter, lightRadius); + mCanvas->initLight(lightCenter, lightRadius, ambientShadowAlpha, spotShadowAlpha); } void CanvasContext::setOpaque(bool opaque) { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 1bab1b145f51..2a01027884e2 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -53,7 +53,8 @@ public: bool initialize(ANativeWindow* window); void updateSurface(ANativeWindow* window); void pauseSurface(ANativeWindow* window); - void setup(int width, int height, const Vector3& lightCenter, float lightRadius); + void setup(int width, int height, const Vector3& lightCenter, float lightRadius, + uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); void setOpaque(bool opaque); void makeCurrent(); void processLayerUpdate(DeferredLayerUpdater* layerUpdater); diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 763e72747e83..dd34e095738d 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -85,7 +85,8 @@ int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos void DrawFrameTask::postAndWait() { AutoMutex _lock(mLock); - mRenderThread->queueAndWait(this, mSignal, mLock); + mRenderThread->queue(this); + mSignal.wait(mLock); } void DrawFrameTask::run() { diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 91f5801d8b60..3f030936185e 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -39,6 +39,8 @@ namespace renderthread { #define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,) #define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,) #define CREATE_BRIDGE5(name, a1, a2, a3, a4, a5) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,,,) +#define CREATE_BRIDGE6(name, a1, a2, a3, a4, a5, a6) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,,) +#define CREATE_BRIDGE7(name, a1, a2, a3, a4, a5, a6, a7) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,a7,) #define CREATE_BRIDGE(name, a1, a2, a3, a4, a5, a6, a7, a8) \ typedef struct { \ a1; a2; a3; a4; a5; a6; a7; a8; \ @@ -152,19 +154,24 @@ void RenderProxy::pauseSurface(const sp<ANativeWindow>& window) { postAndWait(task); } -CREATE_BRIDGE5(setup, CanvasContext* context, int width, int height, - Vector3 lightCenter, int lightRadius) { - args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius); +CREATE_BRIDGE7(setup, CanvasContext* context, int width, int height, + Vector3 lightCenter, float lightRadius, + uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { + args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius, + args->ambientShadowAlpha, args->spotShadowAlpha); return NULL; } -void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius) { +void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius, + uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { SETUP_TASK(setup); args->context = mContext; args->width = width; args->height = height; args->lightCenter = lightCenter; args->lightRadius = lightRadius; + args->ambientShadowAlpha = ambientShadowAlpha; + args->spotShadowAlpha = spotShadowAlpha; post(task); } @@ -405,7 +412,8 @@ void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) { task->setReturnPtr(&retval); SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition); AutoMutex _lock(mSyncMutex); - mRenderThread.queueAndWait(&syncTask, mSyncCondition, mSyncMutex); + mRenderThread.queue(&syncTask); + mSyncCondition.wait(mSyncMutex); return retval; } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 0027403a3524..28d01731d070 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -67,7 +67,8 @@ public: ANDROID_API bool initialize(const sp<ANativeWindow>& window); ANDROID_API void updateSurface(const sp<ANativeWindow>& window); ANDROID_API void pauseSurface(const sp<ANativeWindow>& window); - ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius); + ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius, + uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); ANDROID_API void setOpaque(bool opaque); ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos, float density); diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 32dc46ee57eb..03e98d5b2f03 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -20,7 +20,6 @@ #include <gui/DisplayEventReceiver.h> #include <utils/Log.h> -#include <pthread.h> #include "../RenderState.h" #include "CanvasContext.h" @@ -137,7 +136,6 @@ public: }; RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>() - , mThreadId(0) , mNextWakeup(LLONG_MAX) , mDisplayEventReceiver(0) , mVsyncRequested(false) @@ -246,7 +244,6 @@ void RenderThread::requestVsync() { } bool RenderThread::threadLoop() { - mThreadId = pthread_self(); initThreadLocals(); int timeoutMillis = -1; @@ -292,16 +289,6 @@ void RenderThread::queue(RenderTask* task) { } } -void RenderThread::queueAndWait(RenderTask* task, Condition& signal, Mutex& lock) { - static nsecs_t sTimeout = milliseconds(500); - queue(task); - status_t err = signal.waitRelative(lock, sTimeout); - if (CC_UNLIKELY(err != NO_ERROR)) { - ALOGE("Timeout waiting for RenderTherad! err=%d", err); - nukeFromOrbit(); - } -} - void RenderThread::queueAtFront(RenderTask* task) { AutoMutex _lock(mLock); mQueue.queueAtFront(task); @@ -354,10 +341,6 @@ RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { return next; } -void RenderThread::nukeFromOrbit() { - pthread_kill(mThreadId, SIGABRT); -} - } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 59843736f048..0b91e9dd97aa 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -23,7 +23,6 @@ #include <set> #include <cutils/compiler.h> -#include <utils/Condition.h> #include <utils/Looper.h> #include <utils/Mutex.h> #include <utils/Singleton.h> @@ -74,7 +73,6 @@ public: // RenderThread takes complete ownership of tasks that are queued // and will delete them after they are run ANDROID_API void queue(RenderTask* task); - void queueAndWait(RenderTask* task, Condition& signal, Mutex& lock); ANDROID_API void queueAtFront(RenderTask* task); void queueDelayed(RenderTask* task, int delayMs); void remove(RenderTask* task); @@ -108,15 +106,11 @@ private: void dispatchFrameCallbacks(); void requestVsync(); - // VERY DANGEROUS HANDLE WITH EXTREME CARE - void nukeFromOrbit(); - // Returns the next task to be run. If this returns NULL nextWakeup is set // to the time to requery for the nextTask to run. mNextWakeup is also // set to this time RenderTask* nextTask(nsecs_t* nextWakeup); - pthread_t mThreadId; sp<Looper> mLooper; Mutex mLock; diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h index 65f16636794c..2dfe9c600ba5 100644 --- a/libs/hwui/utils/MathUtils.h +++ b/libs/hwui/utils/MathUtils.h @@ -19,19 +19,19 @@ namespace android { namespace uirenderer { +#define NON_ZERO_EPSILON (0.001f) + class MathUtils { -private: - static const float gNonZeroEpsilon = 0.001f; public: /** * Check for floats that are close enough to zero. */ inline static bool isZero(float value) { - return (value >= -gNonZeroEpsilon) && (value <= gNonZeroEpsilon); + return (value >= -NON_ZERO_EPSILON) && (value <= NON_ZERO_EPSILON); } inline static bool isPositive(float value) { - return value >= gNonZeroEpsilon; + return value >= NON_ZERO_EPSILON; } inline static bool areEqual(float valueA, float valueB) { diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 64462730e57b..b2d8ffe293bb 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -153,6 +153,7 @@ public final class AudioAttributes implements Parcelable { private int mUsage = USAGE_UNKNOWN; private int mContentType = CONTENT_TYPE_UNKNOWN; + private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID; private int mFlags = 0x0; private HashSet<String> mTags; private String mFormattedTags; @@ -177,6 +178,17 @@ public final class AudioAttributes implements Parcelable { } /** + * @hide + * CANDIDATE FOR PUBLIC API + * Return the capture preset. + * @return one of the values that can be set in {@link Builder#setCapturePreset(int)} or a + * negative value if none has been set. + */ + public int getCapturePreset() { + return mSource; + } + + /** * Return the flags. * @return a combined mask of all flags */ @@ -210,6 +222,7 @@ public final class AudioAttributes implements Parcelable { public static class Builder { private int mUsage = USAGE_UNKNOWN; private int mContentType = CONTENT_TYPE_UNKNOWN; + private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID; private int mFlags = 0x0; private HashSet<String> mTags = new HashSet<String>(); @@ -241,6 +254,7 @@ public final class AudioAttributes implements Parcelable { AudioAttributes aa = new AudioAttributes(); aa.mContentType = mContentType; aa.mUsage = mUsage; + aa.mSource = mSource; aa.mFlags = mFlags; aa.mTags = (HashSet<String>) mTags.clone(); final Iterator<String> tagIterator = mTags.iterator(); @@ -397,9 +411,52 @@ public final class AudioAttributes implements Parcelable { mContentType = CONTENT_TYPE_SPEECH; break; default: - Log.e(TAG, "Invalid stream type " + streamType + " in for AudioAttributes"); + Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes"); + } + return this; + } + + /** + * @hide + * CANDIDATE FOR PUBLIC API + * Sets the capture preset. + * Use this audio attributes configuration method when building an {@link AudioRecord} + * instance with {@link AudioRecord#AudioRecord(AudioAttributes, AudioFormat, int)}. + * @param preset one of {@link MediaRecorder.AudioSource#DEFAULT}, + * {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER}, + * {@link MediaRecorder.AudioSource#VOICE_RECOGNITION} or + * {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}. + * @return the same Builder instance. + */ + public Builder setCapturePreset(int preset) { + switch (preset) { + case MediaRecorder.AudioSource.DEFAULT: + case MediaRecorder.AudioSource.MIC: + case MediaRecorder.AudioSource.CAMCORDER: + case MediaRecorder.AudioSource.VOICE_RECOGNITION: + case MediaRecorder.AudioSource.VOICE_COMMUNICATION: + mSource = preset; + break; + default: + Log.e(TAG, "Invalid capture preset " + preset + " for AudioAttributes"); + } + return this; + } + + /** + * @hide + * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD and + * REMOTE_SUBMIX. + * @param preset + * @return the same Builder instance. + */ + public Builder setInternalCapturePreset(int preset) { + if ((preset == MediaRecorder.AudioSource.HOTWORD) + || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX)) { + mSource = preset; + } else { + setCapturePreset(preset); } - mUsage = usageForLegacyStreamType(streamType); return this; } }; @@ -425,6 +482,7 @@ public final class AudioAttributes implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mUsage); dest.writeInt(mContentType); + dest.writeInt(mSource); dest.writeInt(mFlags); dest.writeInt(flags & ALL_PARCEL_FLAGS); if ((flags & FLATTEN_TAGS) == 0) { @@ -439,6 +497,7 @@ public final class AudioAttributes implements Parcelable { private AudioAttributes(Parcel in) { mUsage = in.readInt(); mContentType = in.readInt(); + mSource = in.readInt(); mFlags = in.readInt(); boolean hasFlattenedTags = ((in.readInt() & FLATTEN_TAGS) == FLATTEN_TAGS); mTags = new HashSet<String>(); diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 9f908cfc97f4..2a612e858b8a 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -128,6 +128,15 @@ public class AudioFormat { /** * @hide + * Return the number of channels from an input channel mask + * @param mask a combination of the CHANNEL_IN_* definitions, even CHANNEL_IN_DEFAULT + * @return number of channels for the mask + */ + public static int channelCountFromInChannelMask(int mask) { + return Integer.bitCount(mask); + } + /** + * @hide * Return the number of channels from an output channel mask * @param mask a combination of the CHANNEL_OUT_* definitions, but not CHANNEL_OUT_DEFAULT * @return number of channels for the mask diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 52608a9373f6..111612756c95 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -27,7 +27,10 @@ import android.content.Intent; import android.media.RemoteController.OnClientUpdateListener; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicyConfig; +import android.media.session.MediaController; +import android.media.session.MediaSession; import android.media.session.MediaSessionLegacyHelper; +import android.media.session.MediaSessionManager; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -354,6 +357,12 @@ public class AudioManager { public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9; /** + * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders. + * @hide + */ + public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10; + + /** * Ringer mode that will be silent and will not vibrate. (This overrides the * vibrate setting.) * @@ -2212,7 +2221,9 @@ public class AudioManager { * that will receive the media button intent. This broadcast receiver must be declared * in the application manifest. The package of the component must match that of * the context you're registering from. + * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. */ + @Deprecated public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { if (eventReceiver == null) { return; @@ -2238,9 +2249,12 @@ public class AudioManager { * you know you will continue running for the full time until unregistering the * PendingIntent. * @param eventReceiver target that will receive media button intents. The PendingIntent - * will be sent as-is when a media button action occurs, with {@link Intent#EXTRA_KEY_EVENT} - * added and holding the key code of the media button that was pressed. + * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action + * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the + * media button that was pressed. + * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. */ + @Deprecated public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) { if (eventReceiver == null) { return; @@ -2265,7 +2279,9 @@ public class AudioManager { * Unregister the receiver of MEDIA_BUTTON intents. * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}. + * @deprecated Use {@link MediaSession} instead. */ + @Deprecated public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { if (eventReceiver == null) { return; @@ -2283,7 +2299,9 @@ public class AudioManager { * Unregister the receiver of MEDIA_BUTTON intents. * @param eventReceiver same PendingIntent that was registed with * {@link #registerMediaButtonEventReceiver(PendingIntent)}. + * @deprecated Use {@link MediaSession} instead. */ + @Deprecated public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) { if (eventReceiver == null) { return; @@ -2305,7 +2323,9 @@ public class AudioManager { * @param rcClient The remote control client from which remote controls will receive * information to display. * @see RemoteControlClient + * @deprecated Use {@link MediaSession} instead. */ + @Deprecated public void registerRemoteControlClient(RemoteControlClient rcClient) { if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { return; @@ -2318,7 +2338,9 @@ public class AudioManager { * remote controls. * @param rcClient The remote control client to unregister. * @see #registerRemoteControlClient(RemoteControlClient) + * @deprecated Use {@link MediaSession} instead. */ + @Deprecated public void unregisterRemoteControlClient(RemoteControlClient rcClient) { if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { return; @@ -2336,7 +2358,11 @@ public class AudioManager { * @param rctlr the object to register. * @return true if the {@link RemoteController} was successfully registered, false if an * error occurred, due to an internal system error, or insufficient permissions. + * @deprecated Use + * {@link MediaSessionManager#addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, ComponentName)} + * and {@link MediaController} instead. */ + @Deprecated public boolean registerRemoteController(RemoteController rctlr) { if (rctlr == null) { return false; @@ -2349,7 +2375,11 @@ public class AudioManager { * Unregisters a {@link RemoteController}, causing it to no longer receive media metadata and * playback state information, and no longer be capable of controlling playback. * @param rctlr the object to unregister. + * @deprecated Use + * {@link MediaSessionManager#removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener)} + * instead. */ + @Deprecated public void unregisterRemoteController(RemoteController rctlr) { if (rctlr == null) { return; diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index d4e85c810d65..5be6371ee998 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -180,6 +180,10 @@ public class AudioRecord * Audio session ID */ private int mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE; + /** + * AudioAttributes + */ + private AudioAttributes mAudioAttributes; //--------------------------------------------------------- // Constructor, Finalize @@ -189,8 +193,8 @@ public class AudioRecord * Though some invalid parameters will result in an {@link IllegalArgumentException} exception, * other errors do not. Thus you should call {@link #getState()} immediately after construction * to confirm that the object is usable. - * @param audioSource the recording source. See {@link MediaRecorder.AudioSource} for - * recording source definitions. + * @param audioSource the recording source (also referred to as capture preset). + * See {@link MediaRecorder.AudioSource} for the capture preset definitions. * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only * rate that is guaranteed to work on all devices, but other rates such as 22050, * 16000, and 11025 may work on some devices. @@ -211,24 +215,89 @@ public class AudioRecord public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes) throws IllegalArgumentException { + this((new AudioAttributes.Builder()) + .setInternalCapturePreset(audioSource) + .build(), + (new AudioFormat.Builder()) + .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig, + true/*allow legacy configurations*/)) + .setEncoding(audioFormat) + .setSampleRate(sampleRateInHz) + .build(), + bufferSizeInBytes, + AudioManager.AUDIO_SESSION_ID_GENERATE); + } + + /** + * @hide + * CANDIDATE FOR PUBLIC API + * Class constructor with {@link AudioAttributes} and {@link AudioFormat}. + * @param attributes a non-null {@link AudioAttributes} instance. Use + * {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the capture + * preset for this instance. + * @param format a non-null {@link AudioFormat} instance describing the format of the data + * that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for + * configuring the audio format parameters such as encoding, channel mask and sample rate. + * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written + * to during the recording. New audio data can be read from this buffer in smaller chunks + * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum + * required buffer size for the successful creation of an AudioRecord instance. Using values + * smaller than getMinBufferSize() will result in an initialization failure. + * @param sessionId ID of audio session the AudioRecord must be attached to, or + * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction + * time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before + * construction. + * @throws IllegalArgumentException + */ + public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, + int sessionId) throws IllegalArgumentException { mRecordingState = RECORDSTATE_STOPPED; + if (attributes == null) { + throw new IllegalArgumentException("Illegal null AudioAttributes"); + } + if (format == null) { + throw new IllegalArgumentException("Illegal null AudioFormat"); + } + // remember which looper is associated with the AudioRecord instanciation if ((mInitializationLooper = Looper.myLooper()) == null) { mInitializationLooper = Looper.getMainLooper(); } - audioParamCheck(audioSource, sampleRateInHz, channelConfig, audioFormat); + mAudioAttributes = attributes; + + int rate = 0; + if ((format.getPropertySetMask() + & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0) + { + rate = format.getSampleRate(); + } else { + rate = AudioSystem.getPrimaryOutputSamplingRate(); + if (rate <= 0) { + rate = 44100; + } + } + + int encoding = AudioFormat.ENCODING_DEFAULT; + if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0) + { + encoding = format.getEncoding(); + } + + audioParamCheck(attributes.getCapturePreset(), rate, encoding); + + mChannelCount = AudioFormat.channelCountFromInChannelMask(format.getChannelMask()); + mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false); audioBuffSizeCheck(bufferSizeInBytes); - // native initialization int[] session = new int[1]; - session[0] = AudioSystem.AUDIO_SESSION_ALLOCATE; + session[0] = sessionId; //TODO: update native initialization when information about hardware init failure // due to capture device already open is available. int initResult = native_setup( new WeakReference<AudioRecord>(this), - mRecordSource, mSampleRate, mChannelMask, mAudioFormat, mNativeBufferSizeInBytes, + mAudioAttributes, mSampleRate, mChannelMask, mAudioFormat, mNativeBufferSizeInBytes, session); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing native AudioRecord object."); @@ -240,17 +309,42 @@ public class AudioRecord mState = STATE_INITIALIZED; } - // Convenience method for the constructor's parameter checks. - // This and audioBuffSizeCheck are where constructor IllegalArgumentException-s are thrown + // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor + // IllegalArgumentException-s are thrown + private static int getChannelMaskFromLegacyConfig(int inChannelConfig, + boolean allowLegacyConfig) { + int mask; + switch (inChannelConfig) { + case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT + case AudioFormat.CHANNEL_IN_MONO: + case AudioFormat.CHANNEL_CONFIGURATION_MONO: + mask = AudioFormat.CHANNEL_IN_MONO; + break; + case AudioFormat.CHANNEL_IN_STEREO: + case AudioFormat.CHANNEL_CONFIGURATION_STEREO: + mask = AudioFormat.CHANNEL_IN_STEREO; + break; + case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK): + mask = inChannelConfig; + break; + default: + throw new IllegalArgumentException("Unsupported channel configuration."); + } + + if (!allowLegacyConfig && ((inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO) + || (inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_STEREO))) { + // only happens with the constructor that uses AudioAttributes and AudioFormat + throw new IllegalArgumentException("Unsupported deprecated configuration."); + } + + return mask; + } // postconditions: // mRecordSource is valid - // mChannelCount is valid - // mChannelMask is valid // mAudioFormat is valid // mSampleRate is valid - private void audioParamCheck(int audioSource, int sampleRateInHz, - int channelConfig, int audioFormat) + private void audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat) throws IllegalArgumentException { //-------------- @@ -271,28 +365,6 @@ public class AudioRecord mSampleRate = sampleRateInHz; //-------------- - // channel config - switch (channelConfig) { - case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT - case AudioFormat.CHANNEL_IN_MONO: - case AudioFormat.CHANNEL_CONFIGURATION_MONO: - mChannelCount = 1; - mChannelMask = AudioFormat.CHANNEL_IN_MONO; - break; - case AudioFormat.CHANNEL_IN_STEREO: - case AudioFormat.CHANNEL_CONFIGURATION_STEREO: - mChannelCount = 2; - mChannelMask = AudioFormat.CHANNEL_IN_STEREO; - break; - case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK): - mChannelCount = 2; - mChannelMask = channelConfig; - break; - default: - throw new IllegalArgumentException("Unsupported channel configuration."); - } - - //-------------- // audio format switch (audioFormat) { case AudioFormat.ENCODING_DEFAULT: @@ -804,7 +876,8 @@ public class AudioRecord //-------------------- private native final int native_setup(Object audiorecord_this, - int recordSource, int sampleRate, int channelMask, int audioFormat, + Object /*AudioAttributes*/ attributes, + int sampleRate, int channelMask, int audioFormat, int buffSizeInBytes, int[] sessionId); private native final void native_finalize(); diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index ef42549ec061..ae7c50130c89 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -44,6 +44,7 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.database.ContentObserver; import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiPlaybackClient; import android.hardware.hdmi.HdmiTvClient; import android.hardware.usb.UsbManager; import android.media.MediaPlayer.OnCompletionListener; @@ -70,6 +71,7 @@ import android.provider.Settings.System; import android.telecomm.TelecommManager; import android.text.TextUtils; import android.util.Log; +import android.util.MathUtils; import android.util.Slog; import android.view.KeyEvent; import android.view.Surface; @@ -144,7 +146,23 @@ public class AudioService extends IAudioService.Stub { private final Context mContext; private final ContentResolver mContentResolver; private final AppOpsManager mAppOps; - private final boolean mVoiceCapable; + + // the platform has no specific capabilities + private static final int PLATFORM_DEFAULT = 0; + // the platform is voice call capable (a phone) + private static final int PLATFORM_VOICE = 1; + // the platform is a television or a set-top box + private static final int PLATFORM_TELEVISION = 2; + // the platform type affects volume and silent mode behavior + private final int mPlatformType; + + private boolean isPlatformVoice() { + return mPlatformType == PLATFORM_VOICE; + } + + private boolean isPlatformTelevision() { + return mPlatformType == PLATFORM_TELEVISION; + } /** The controller for the volume UI. */ private final VolumeController mVolumeController = new VolumeController(); @@ -180,6 +198,7 @@ public class AudioService extends IAudioService.Stub { private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19; private static final int MSG_UNLOAD_SOUND_EFFECTS = 20; private static final int MSG_SYSTEM_READY = 21; + private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) @@ -243,9 +262,10 @@ public class AudioService extends IAudioService.Stub { * NOTE: do not create loops in aliases! * Some streams alias to different streams according to device category (phone or tablet) or * use case (in call vs off call...). See updateStreamVolumeAlias() for more details. - * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and - * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ - private final int[] STREAM_VOLUME_ALIAS = new int[] { + * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device + * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and + * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/ + private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_RING, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING @@ -257,7 +277,19 @@ public class AudioService extends IAudioService.Stub { AudioSystem.STREAM_RING, // STREAM_DTMF AudioSystem.STREAM_MUSIC // STREAM_TTS }; - private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { + private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] { + AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL + AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM + AudioSystem.STREAM_MUSIC, // STREAM_RING + AudioSystem.STREAM_MUSIC, // STREAM_MUSIC + AudioSystem.STREAM_MUSIC, // STREAM_ALARM + AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION + AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO + AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED + AudioSystem.STREAM_MUSIC, // STREAM_DTMF + AudioSystem.STREAM_MUSIC // STREAM_TTS + }; + private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING @@ -455,9 +487,12 @@ public class AudioService extends IAudioService.Stub { public final static int STREAM_REMOTE_MUSIC = -200; // Devices for which the volume is fixed and VolumePanel slider should be disabled - final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | + int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | - AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; + AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | + AudioSystem.DEVICE_OUT_HDMI_ARC | + AudioSystem.DEVICE_OUT_SPDIF | + AudioSystem.DEVICE_OUT_AUX_LINE; // TODO merge orientation and rotation private final boolean mMonitorOrientation; @@ -491,8 +526,16 @@ public class AudioService extends IAudioService.Stub { mContext = context; mContentResolver = context.getContentResolver(); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); - mVoiceCapable = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_voice_capable); + + if (mContext.getResources().getBoolean( + com.android.internal.R.bool.config_voice_capable)) { + mPlatformType = PLATFORM_VOICE; + } else if (context.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TELEVISION)) { + mPlatformType = PLATFORM_TELEVISION; + } else { + mPlatformType = PLATFORM_DEFAULT; + } PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent"); @@ -622,10 +665,15 @@ public class AudioService extends IAudioService.Stub { BluetoothProfile.A2DP); } - HdmiControlManager hdmiManager = + mHdmiManager = (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE); - // Null if device is not Tv. - mHdmiTvClient = hdmiManager.getTvClient(); + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + mHdmiTvClient = mHdmiManager.getTvClient(); + mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); + mHdmiCecSink = false; + } + } sendMsg(mAudioHandler, MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED, @@ -670,6 +718,14 @@ public class AudioService extends IAudioService.Stub { } } + private void checkAllFixedVolumeDevices() + { + int numStreamTypes = AudioSystem.getNumStreamTypes(); + for (int streamType = 0; streamType < numStreamTypes; streamType++) { + mStreamStates[streamType].checkFixedVolumeDevices(); + } + } + private void createStreamStates() { int numStreamTypes = AudioSystem.getNumStreamTypes(); VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; @@ -678,6 +734,7 @@ public class AudioService extends IAudioService.Stub { streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); } + checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); } @@ -702,19 +759,32 @@ public class AudioService extends IAudioService.Stub { private void updateStreamVolumeAlias(boolean updateVolumes) { int dtmfStreamAlias; - if (mVoiceCapable) { - mStreamVolumeAlias = STREAM_VOLUME_ALIAS; + + switch (mPlatformType) { + case PLATFORM_VOICE: + mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE; dtmfStreamAlias = AudioSystem.STREAM_RING; - } else { - mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; + break; + case PLATFORM_TELEVISION: + mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION; + dtmfStreamAlias = AudioSystem.STREAM_MUSIC; + break; + default: + mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT; dtmfStreamAlias = AudioSystem.STREAM_MUSIC; } - if (isInCommunication()) { - dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; - mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF); + + if (isPlatformTelevision()) { + mRingerModeAffectedStreams = 0; } else { - mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF); + if (isInCommunication()) { + dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; + mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF); + } else { + mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF); + } } + mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; if (updateVolumes) { mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]); @@ -768,7 +838,7 @@ public class AudioService extends IAudioService.Stub { if (ringerMode != ringerModeFromSettings) { Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode); } - if (mUseFixedVolume) { + if (mUseFixedVolume || isPlatformTelevision()) { ringerMode = AudioManager.RINGER_MODE_NORMAL; } synchronized(mSettingsLock) { @@ -815,9 +885,6 @@ public class AudioService extends IAudioService.Stub { broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); - // Restore the default media button receiver from the system settings - mMediaFocusControl.restoreMediaButtonReceiver(); - // Load settings for the volume controller mVolumeController.loadSettings(cr); } @@ -1001,15 +1068,30 @@ public class AudioService extends IAudioService.Stub { // Check if volume update should be send to Hdmi system audio. int newIndex = mStreamStates[streamType].getIndex(device); - if (mHdmiTvClient != null && - streamTypeAlias == AudioSystem.STREAM_MUSIC && - (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 && - oldIndex != newIndex) { - int maxIndex = getStreamMaxVolume(streamType); - synchronized (mHdmiTvClient) { - if (mHdmiSystemAudioSupported) { - mHdmiTvClient.setSystemAudioVolume( - (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex); + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + if (mHdmiTvClient != null && + streamTypeAlias == AudioSystem.STREAM_MUSIC && + (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 && + oldIndex != newIndex) { + int maxIndex = getStreamMaxVolume(streamType); + synchronized (mHdmiTvClient) { + if (mHdmiSystemAudioSupported) { + mHdmiTvClient.setSystemAudioVolume( + (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex); + } + } + } + // mHdmiCecSink true => mHdmiPlaybackClient != null + if (mHdmiCecSink && + streamTypeAlias == AudioSystem.STREAM_MUSIC && + oldIndex != newIndex) { + synchronized (mHdmiPlaybackClient) { + int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN : + KeyEvent.KEYCODE_VOLUME_UP; + mHdmiPlaybackClient.sendKeyEvent(keyCode, true); + mHdmiPlaybackClient.sendKeyEvent(keyCode, false); + } } } } @@ -1051,6 +1133,13 @@ public class AudioService extends IAudioService.Stub { mFlags = flags; mDevice = device; } + + @Override + public String toString() { + return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=") + .append(mIndex).append(",flags=").append(mFlags).append(",device=") + .append(mDevice).append('}').toString(); + } }; private void onSetStreamVolume(int streamType, int index, int flags, int device) { @@ -1113,15 +1202,19 @@ public class AudioService extends IAudioService.Stub { } } - if (mHdmiTvClient != null && - streamTypeAlias == AudioSystem.STREAM_MUSIC && - (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 && - oldIndex != index) { - int maxIndex = getStreamMaxVolume(streamType); - synchronized (mHdmiTvClient) { - if (mHdmiSystemAudioSupported) { - mHdmiTvClient.setSystemAudioVolume( - (oldIndex + 5) / 10, (index + 5) / 10, maxIndex); + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + if (mHdmiTvClient != null && + streamTypeAlias == AudioSystem.STREAM_MUSIC && + (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 && + oldIndex != index) { + int maxIndex = getStreamMaxVolume(streamType); + synchronized (mHdmiTvClient) { + if (mHdmiSystemAudioSupported) { + mHdmiTvClient.setSystemAudioVolume( + (oldIndex + 5) / 10, (index + 5) / 10, maxIndex); + } + } } } } @@ -1260,7 +1353,7 @@ public class AudioService extends IAudioService.Stub { // UI update and Broadcast Intent private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { - if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { + if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) { streamType = AudioSystem.STREAM_NOTIFICATION; } @@ -1349,10 +1442,14 @@ public class AudioService extends IAudioService.Stub { } if (isStreamAffectedByMute(streamType)) { - if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) { - synchronized (mHdmiTvClient) { - if (mHdmiSystemAudioSupported) { - mHdmiTvClient.setSystemAudioMute(state); + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) { + synchronized (mHdmiTvClient) { + if (mHdmiSystemAudioSupported) { + mHdmiTvClient.setSystemAudioMute(state); + } + } } } } @@ -1475,11 +1572,15 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#getMasterStreamType() */ public int getMasterStreamType() { - if (mVoiceCapable) { - return AudioSystem.STREAM_RING; - } else { - return AudioSystem.STREAM_NOTIFICATION; + switch (mPlatformType) { + case PLATFORM_VOICE: + return AudioSystem.STREAM_RING; + case PLATFORM_TELEVISION: + return AudioSystem.STREAM_MUSIC; + default: + break; } + return AudioSystem.STREAM_NOTIFICATION; } /** @see AudioManager#setMicrophoneMute(boolean) */ @@ -1507,7 +1608,7 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#setRingerMode(int) */ public void setRingerMode(int ringerMode) { - if (mUseFixedVolume) { + if (mUseFixedVolume || isPlatformTelevision()) { return; } @@ -1537,7 +1638,7 @@ public class AudioService extends IAudioService.Stub { ringerMode == AudioManager.RINGER_MODE_NORMAL) { // ring and notifications volume should never be 0 when not silenced // on voice capable devices - if (mVoiceCapable && + if (isPlatformVoice() && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { synchronized (mStreamStates[streamType]) { Set set = mStreamStates[streamType].mIndex.entrySet(); @@ -2044,9 +2145,13 @@ public class AudioService extends IAudioService.Stub { // muted by ringer mode have the correct volume setRingerModeInt(getRingerMode(), false); + checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); synchronized (mSafeMediaVolumeState) { + mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver, + Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT), + 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX); if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) { enforceSafeMediaVolume(); } @@ -2619,20 +2724,27 @@ public class AudioService extends IAudioService.Stub { setSafeMediaVolumeEnabled(true); mMusicActiveMs = 0; } + saveMusicActiveMs(); } } } } } + private void saveMusicActiveMs() { + mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget(); + } + private void onConfigureSafeVolume(boolean force) { synchronized (mSafeMediaVolumeState) { int mcc = mContext.getResources().getConfiguration().mcc; if ((mMcc != mcc) || ((mMcc == 0) && force)) { mSafeMediaVolumeIndex = mContext.getResources().getInteger( com.android.internal.R.integer.config_safe_media_volume_index) * 10; - boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_safe_media_volume_enabled); + boolean safeMediaVolumeEnabled = + SystemProperties.getBoolean("audio.safemedia.force", false) + || mContext.getResources().getBoolean( + com.android.internal.R.bool.config_safe_media_volume_enabled); // The persisted state is either "disabled" or "active": this is the state applied // next time we boot and cannot be "inactive" @@ -2643,8 +2755,13 @@ public class AudioService extends IAudioService.Stub { // the 30 seconds timeout for forced configuration. In this case we don't reset // it to "active". if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) { - mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; - enforceSafeMediaVolume(); + if (mMusicActiveMs == 0) { + mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; + enforceSafeMediaVolume(); + } else { + // We have existing playback time recorded, already confirmed. + mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE; + } } } else { persistedState = SAFE_MEDIA_VOLUME_DISABLED; @@ -2763,11 +2880,18 @@ public class AudioService extends IAudioService.Stub { (1 << AudioSystem.STREAM_NOTIFICATION)| (1 << AudioSystem.STREAM_SYSTEM); - if (mVoiceCapable) { - ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); - } else { - ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); + switch (mPlatformType) { + case PLATFORM_VOICE: + ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); + break; + case PLATFORM_TELEVISION: + ringerModeAffectedStreams = 0; + break; + default: + ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); + break; } + synchronized (mCameraSoundForced) { if (mCameraSoundForced) { ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); @@ -2836,7 +2960,8 @@ public class AudioService extends IAudioService.Stub { } private int getActiveStreamType(int suggestedStreamType) { - if (mVoiceCapable) { + switch (mPlatformType) { + case PLATFORM_VOICE: if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { @@ -2866,12 +2991,26 @@ public class AudioService extends IAudioService.Stub { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); return AudioSystem.STREAM_MUSIC; - } else { - if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " - + suggestedStreamType); - return suggestedStreamType; } - } else { + break; + case PLATFORM_TELEVISION: + if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { + if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) { + if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC"); + return AudioSystem.STREAM_MUSIC; + } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive( + AudioSystem.STREAM_MUSIC)) { + if (DEBUG_VOL) + Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); + return STREAM_REMOTE_MUSIC; + } else { + if (DEBUG_VOL) Log.v(TAG, + "getActiveStreamType: using STREAM_MUSIC as default"); + return AudioSystem.STREAM_MUSIC; + } + } + break; + default: if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { @@ -2902,12 +3041,12 @@ public class AudioService extends IAudioService.Stub { "getActiveStreamType: using STREAM_NOTIFICATION as default"); return AudioSystem.STREAM_NOTIFICATION; } - } else { - if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " - + suggestedStreamType); - return suggestedStreamType; } + break; } + if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " + + suggestedStreamType); + return suggestedStreamType; } private void broadcastRingerMode(int ringerMode) { @@ -3101,13 +3240,7 @@ public class AudioService extends IAudioService.Stub { continue; } - // ignore settings for fixed volume devices: volume should always be at max or 0 - if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) && - ((device & mFixedVolumeDevices) != 0)) { - mIndex.put(device, (index != 0) ? mIndexMax : 0); - } else { - mIndex.put(device, getValidIndex(10 * index)); - } + mIndex.put(device, getValidIndex(10 * index)); } } } @@ -3266,6 +3399,25 @@ public class AudioService extends IAudioService.Stub { return mStreamType; } + public void checkFixedVolumeDevices() { + synchronized (VolumeStreamState.class) { + // ignore settings for fixed volume devices: volume should always be at max or 0 + if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) { + Set set = mIndex.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + int device = ((Integer)entry.getKey()).intValue(); + int index = ((Integer)entry.getValue()).intValue(); + if (((device & mFixedVolumeDevices) != 0) && index != 0) { + entry.setValue(mIndexMax); + } + applyDeviceVolume(device); + } + } + } + } + private int getValidIndex(int index) { if (index < 0) { return 0; @@ -3472,6 +3624,9 @@ public class AudioService extends IAudioService.Stub { if (mUseFixedVolume) { return; } + if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) { + return; + } System.putIntForUser(mContentResolver, streamState.getSettingNameForDevice(device), (streamState.getIndex(device) + 5)/ 10, @@ -3828,11 +3983,13 @@ public class AudioService extends IAudioService.Stub { mDockAudioMediaEnabled ? AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE); } - - if (mHdmiTvClient != null) { - setHdmiSystemAudioSupported(mHdmiSystemAudioSupported); + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + if (mHdmiTvClient != null) { + setHdmiSystemAudioSupported(mHdmiSystemAudioSupported); + } + } } - // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); break; @@ -3932,6 +4089,13 @@ public class AudioService extends IAudioService.Stub { case MSG_SYSTEM_READY: onSystemReady(); break; + + case MSG_PERSIST_MUSIC_ACTIVE_MS: + final int musicActiveMs = msg.arg1; + Settings.Secure.putIntForUser(mContentResolver, + Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs, + UserHandle.USER_CURRENT); + break; } } } @@ -4278,6 +4442,27 @@ public class AudioService extends IAudioService.Stub { null, MUSIC_ACTIVE_POLL_PERIOD_MS); } + // Television devices without CEC service apply software volume on HDMI output + if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) { + mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; + checkAllFixedVolumeDevices(); + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + if (mHdmiPlaybackClient != null) { + mHdmiCecSink = false; + mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback); + } + } + } + } + } else { + if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) { + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + mHdmiCecSink = false; + } + } + } } if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) { sendDeviceConnectionIntent(device, state, name); @@ -4580,18 +4765,20 @@ public class AudioService extends IAudioService.Stub { if (cameraSoundForced != mCameraSoundForced) { mCameraSoundForced = cameraSoundForced; - VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED]; - if (cameraSoundForced) { - s.setAllIndexesToMax(); - mRingerModeAffectedStreams &= - ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); - } else { - s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]); - mRingerModeAffectedStreams |= - (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + if (!isPlatformTelevision()) { + VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED]; + if (cameraSoundForced) { + s.setAllIndexesToMax(); + mRingerModeAffectedStreams &= + ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + } else { + s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]); + mRingerModeAffectedStreams |= + (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + } + // take new state into account for streams muted by ringer mode + setRingerModeInt(getRingerMode(), false); } - // take new state into account for streams muted by ringer mode - setRingerModeInt(getRingerMode(), false); sendMsg(mAudioHandler, MSG_SET_FORCE_USE, @@ -4707,10 +4894,10 @@ public class AudioService extends IAudioService.Stub { // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume() // (when user opts out). - private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0; - private final int SAFE_MEDIA_VOLUME_DISABLED = 1; - private final int SAFE_MEDIA_VOLUME_INACTIVE = 2; - private final int SAFE_MEDIA_VOLUME_ACTIVE = 3; + private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0; + private static final int SAFE_MEDIA_VOLUME_DISABLED = 1; + private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed + private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed private Integer mSafeMediaVolumeState; private int mMcc = 0; @@ -4736,7 +4923,8 @@ public class AudioService extends IAudioService.Stub { enforceSafeMediaVolume(); } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) { mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE; - mMusicActiveMs = 0; + mMusicActiveMs = 1; // nonzero = confirmed + saveMusicActiveMs(); sendMsg(mAudioHandler, MSG_CHECK_MUSIC_ACTIVE, SENDMSG_REPLACE, @@ -4807,27 +4995,57 @@ public class AudioService extends IAudioService.Stub { // to HdmiControlService so that audio recevier can handle volume change. //========================================================================================== + private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback { + public void onComplete(int status) { + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN); + // Television devices without CEC service apply software volume on HDMI output + if (isPlatformTelevision() && !mHdmiCecSink) { + mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; + } + checkAllFixedVolumeDevices(); + } + } + } + }; + // If HDMI-CEC system audio is supported private boolean mHdmiSystemAudioSupported = false; // Set only when device is tv. private HdmiTvClient mHdmiTvClient; + // true if the device has system feature PackageManager.FEATURE_TELEVISION. + // cached HdmiControlManager interface + private HdmiControlManager mHdmiManager; + // Set only when device is a set-top box. + private HdmiPlaybackClient mHdmiPlaybackClient; + // true if we are a set-top box, an HDMI sink is connected and it supports CEC. + private boolean mHdmiCecSink; + + private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback(); @Override public int setHdmiSystemAudioSupported(boolean on) { - if (mHdmiTvClient == null) { - Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode."); - return AudioSystem.DEVICE_NONE; - } + int device = AudioSystem.DEVICE_NONE; + if (mHdmiManager != null) { + synchronized (mHdmiManager) { + if (mHdmiTvClient == null) { + Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode."); + return device; + } - synchronized (mHdmiTvClient) { - if (mHdmiSystemAudioSupported == on) { - return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); + synchronized (mHdmiTvClient) { + if (mHdmiSystemAudioSupported != on) { + mHdmiSystemAudioSupported = on; + AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO, + on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : + AudioSystem.FORCE_NONE); + } + device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); + } } - mHdmiSystemAudioSupported = on; - AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO, - on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE); } - return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); + return device; } //========================================================================================== @@ -4872,7 +5090,25 @@ public class AudioService extends IAudioService.Stub { pw.println("\nAudio routes:"); pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName); + + pw.println("\nOther state:"); pw.print(" mVolumeController="); pw.println(mVolumeController); + pw.print(" mSafeMediaVolumeState="); + pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState)); + pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex); + pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand); + pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs); + pw.print(" mMcc="); pw.println(mMcc); + } + + private static String safeMediaVolumeStateToString(Integer state) { + switch(state) { + case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED"; + case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED"; + case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE"; + case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE"; + } + return null; } // Inform AudioFlinger of our device's low RAM attribute diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java index f9e49c12ec2c..8883d28a9349 100644 --- a/media/java/android/media/CamcorderProfile.java +++ b/media/java/android/media/CamcorderProfile.java @@ -149,6 +149,39 @@ public class CamcorderProfile private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2160P; /** + * High speed ( >= 100fps) quality level corresponding to the lowest available resolution. + */ + public static final int QUALITY_HIGH_SPEED_LOW = 2000; + + /** + * High speed ( >= 100fps) quality level corresponding to the highest available resolution. + */ + public static final int QUALITY_HIGH_SPEED_HIGH = 2001; + + /** + * High speed ( >= 100fps) quality level corresponding to the 480p (720 x 480) resolution. + * + * Note that the horizontal resolution for 480p can also be other + * values, such as 640 or 704, instead of 720. + */ + public static final int QUALITY_HIGH_SPEED_480P = 2002; + + /** + * High speed ( >= 100fps) quality level corresponding to the 720p (1280 x 720) resolution. + */ + public static final int QUALITY_HIGH_SPEED_720P = 2003; + + /** + * High speed ( >= 100fps) quality level corresponding to the 1080p (1920 x 1080 or 1920x1088) + * resolution. + */ + public static final int QUALITY_HIGH_SPEED_1080P = 2004; + + // Start and end of high speed quality list + private static final int QUALITY_HIGH_SPEED_LIST_START = QUALITY_HIGH_SPEED_LOW; + private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_1080P; + + /** * Default recording duration in seconds before the session is terminated. * This is useful for applications like MMS has limited file size requirement. */ @@ -240,13 +273,17 @@ public class CamcorderProfile * {@link #hasProfile(int, int)}. * QUALITY_LOW refers to the lowest quality available, while QUALITY_HIGH refers to * the highest quality available. - * QUALITY_LOW/QUALITY_HIGH have to match one of qcif, cif, 480p, 720p, or 1080p. - * E.g. if the device supports 480p, 720p, and 1080p, then low is 480p and high is - * 1080p. + * QUALITY_LOW/QUALITY_HIGH have to match one of qcif, cif, 480p, 720p, 1080p or 2160p. + * E.g. if the device supports 480p, 720p, 1080p and 2160p, then low is 480p and high is + * 2160p. * * The same is true for time lapse quality levels, i.e. QUALITY_TIME_LAPSE_LOW, * QUALITY_TIME_LAPSE_HIGH are guaranteed to be supported and have to match one of - * qcif, cif, 480p, 720p, or 1080p. + * qcif, cif, 480p, 720p, 1080p, or 2160p. + * + * For high speed quality levels, they may or may not be supported. If a subset of the levels + * are supported, QUALITY_HIGH_SPEED_LOW and QUALITY_HIGH_SPEED_HIGH are guaranteed to be + * supported and have to match one of 480p, 720p, or 1080p. * * A camcorder recording session with higher quality level usually has higher output * bit rate, better video and/or audio recording quality, larger video frame @@ -262,6 +299,7 @@ public class CamcorderProfile * @see #QUALITY_480P * @see #QUALITY_720P * @see #QUALITY_1080P + * @see #QUALITY_2160P * @see #QUALITY_TIME_LAPSE_LOW * @see #QUALITY_TIME_LAPSE_HIGH * @see #QUALITY_TIME_LAPSE_QCIF @@ -269,12 +307,20 @@ public class CamcorderProfile * @see #QUALITY_TIME_LAPSE_480P * @see #QUALITY_TIME_LAPSE_720P * @see #QUALITY_TIME_LAPSE_1080P - */ + * @see #QUALITY_TIME_LAPSE_2160P + * @see #QUALITY_HIGH_SPEED_LOW + * @see #QUALITY_HIGH_SPEED_HIGH + * @see #QUALITY_HIGH_SPEED_480P + * @see #QUALITY_HIGH_SPEED_720P + * @see #QUALITY_HIGH_SPEED_1080P + */ public static CamcorderProfile get(int cameraId, int quality) { if (!((quality >= QUALITY_LIST_START && quality <= QUALITY_LIST_END) || (quality >= QUALITY_TIME_LAPSE_LIST_START && - quality <= QUALITY_TIME_LAPSE_LIST_END))) { + quality <= QUALITY_TIME_LAPSE_LIST_END) || + (quality >= QUALITY_HIGH_SPEED_LIST_START && + quality <= QUALITY_HIGH_SPEED_LIST_END))) { String errMessage = "Unsupported quality level: " + quality; throw new IllegalArgumentException(errMessage); } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index f84c38322073..275d9b203534 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -16,7 +16,10 @@ package android.media; +import android.graphics.ImageFormat; +import android.graphics.Rect; import android.media.Image; +import android.media.Image.Plane; import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.media.MediaCrypto; @@ -29,6 +32,7 @@ import android.view.Surface; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.ReadOnlyBufferException; import java.util.Arrays; import java.util.Map; @@ -1537,4 +1541,175 @@ final public class MediaCodec { } private long mNativeContext; + + /** @hide */ + public static class MediaImage extends Image { + private final boolean mIsReadOnly; + private boolean mIsValid; + private final int mWidth; + private final int mHeight; + private final int mFormat; + private long mTimestamp; + private final Plane[] mPlanes; + private final ByteBuffer mBuffer; + private final ByteBuffer mInfo; + private final int mXOffset; + private final int mYOffset; + + private final static int TYPE_YUV = 1; + + public int getFormat() { + checkValid(); + return mFormat; + } + + public int getHeight() { + checkValid(); + return mHeight; + } + + public int getWidth() { + checkValid(); + return mWidth; + } + + public long getTimestamp() { + checkValid(); + return mTimestamp; + } + + public Plane[] getPlanes() { + checkValid(); + return Arrays.copyOf(mPlanes, mPlanes.length); + } + + public void close() { + if (mIsValid) { + java.nio.NioUtils.freeDirectBuffer(mBuffer); + mIsValid = false; + } + } + + /** + * Set the crop rectangle associated with this frame. + * <p> + * The crop rectangle specifies the region of valid pixels in the image, + * using coordinates in the largest-resolution plane. + */ + public void setCropRect(Rect cropRect) { + if (mIsReadOnly) { + throw new ReadOnlyBufferException(); + } + super.setCropRect(cropRect); + } + + private void checkValid() { + if (!mIsValid) { + throw new IllegalStateException("Image is already released"); + } + } + + private int readInt(ByteBuffer buffer, boolean asLong) { + if (asLong) { + return (int)buffer.getLong(); + } else { + return buffer.getInt(); + } + } + + public MediaImage( + ByteBuffer buffer, ByteBuffer info, boolean readOnly, + long timestamp, int xOffset, int yOffset, Rect cropRect) { + mFormat = ImageFormat.YUV_420_888; + mTimestamp = timestamp; + mIsValid = true; + mIsReadOnly = buffer.isReadOnly(); + mBuffer = buffer.duplicate(); + if (cropRect != null) { + cropRect.offset(-xOffset, -yOffset); + } + mCropRect = cropRect; + + // save offsets and info + mXOffset = xOffset; + mYOffset = yOffset; + mInfo = info; + + // read media-info. the size of media info can be 80 or 156 depending on + // whether it was created on a 32- or 64-bit process. See MediaImage + if (info.remaining() == 80 || info.remaining() == 156) { + boolean sizeIsLong = info.remaining() == 156; + int type = info.getInt(); + if (type != TYPE_YUV) { + throw new UnsupportedOperationException("unsupported type: " + type); + } + int numPlanes = readInt(info, sizeIsLong); + if (numPlanes != 3) { + throw new RuntimeException("unexpected number of planes: " + numPlanes); + } + mWidth = readInt(info, sizeIsLong); + mHeight = readInt(info, sizeIsLong); + if (mWidth < 1 || mHeight < 1) { + throw new UnsupportedOperationException( + "unsupported size: " + mWidth + "x" + mHeight); + } + int bitDepth = readInt(info, sizeIsLong); + if (bitDepth != 8) { + throw new UnsupportedOperationException("unsupported bit depth: " + bitDepth); + } + mPlanes = new MediaPlane[numPlanes]; + for (int ix = 0; ix < numPlanes; ix++) { + int planeOffset = readInt(info, sizeIsLong); + int colInc = readInt(info, sizeIsLong); + int rowInc = readInt(info, sizeIsLong); + int horiz = readInt(info, sizeIsLong); + int vert = readInt(info, sizeIsLong); + if (horiz != vert || horiz != (ix == 0 ? 1 : 2)) { + throw new UnsupportedOperationException("unexpected subsampling: " + + horiz + "x" + vert + " on plane " + ix); + } + + buffer.clear(); + buffer.position(mBuffer.position() + planeOffset + + (xOffset / horiz) * colInc + (yOffset / vert) * rowInc); + buffer.limit(buffer.position() + Utils.divUp(bitDepth, 8) + + (mHeight / vert - 1) * rowInc + (mWidth / horiz - 1) * colInc); + mPlanes[ix] = new MediaPlane(buffer.slice(), rowInc, colInc); + } + } else { + throw new UnsupportedOperationException( + "unsupported info length: " + info.remaining()); + } + } + + private class MediaPlane extends Plane { + public MediaPlane(ByteBuffer buffer, int rowInc, int colInc) { + mData = buffer; + mRowInc = rowInc; + mColInc = colInc; + } + + @Override + public int getRowStride() { + checkValid(); + return mRowInc; + } + + @Override + public int getPixelStride() { + checkValid(); + return mColInc; + } + + @Override + public ByteBuffer getBuffer() { + checkValid(); + return mData; + } + + private final int mRowInc; + private final int mColInc; + private final ByteBuffer mData; + } + } } diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java index 6004ecfe6ffe..c67e3979ec6e 100644 --- a/media/java/android/media/MediaFocusControl.java +++ b/media/java/android/media/MediaFocusControl.java @@ -78,7 +78,6 @@ public class MediaFocusControl implements OnFinished { private final Context mContext; private final ContentResolver mContentResolver; private final AudioService.VolumeController mVolumeController; - private final BroadcastReceiver mReceiver = new PackageIntentsReceiver(); private final AppOpsManager mAppOps; private final KeyguardManager mKeyguardManager; private final AudioService mAudioService; @@ -103,16 +102,6 @@ public class MediaFocusControl implements OnFinished { mContext.getSystemService(Context.TELEPHONY_SERVICE); tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - // Register for package addition/removal/change intent broadcasts - // for media button receiver persistence - IntentFilter pkgFilter = new IntentFilter(); - pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); - pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); - pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); - pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); - pkgFilter.addDataScheme("package"); - mContext.registerReceiver(mReceiver, pkgFilter); - mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); @@ -321,7 +310,6 @@ public class MediaFocusControl implements OnFinished { //========================================================================================== // event handler messages - private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 0; private static final int MSG_RCDISPLAY_CLEAR = 1; private static final int MSG_RCDISPLAY_UPDATE = 2; private static final int MSG_REEVALUATE_REMOTE = 3; @@ -362,10 +350,6 @@ public class MediaFocusControl implements OnFinished { @Override public void handleMessage(Message msg) { switch(msg.what) { - case MSG_PERSIST_MEDIABUTTONRECEIVER: - onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj ); - break; - case MSG_RCDISPLAY_CLEAR: onRcDisplayClear(); break; @@ -874,29 +858,6 @@ public class MediaFocusControl implements OnFinished { } - private class PackageIntentsReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_PACKAGE_REMOVED) - || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) { - if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { - // a package is being removed, not replaced - String packageName = intent.getData().getSchemeSpecificPart(); - if (packageName != null) { - cleanupMediaButtonReceiverForPackage(packageName, true); - } - } - } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) - || action.equals(Intent.ACTION_PACKAGE_CHANGED)) { - String packageName = intent.getData().getSchemeSpecificPart(); - if (packageName != null) { - cleanupMediaButtonReceiverForPackage(packageName, false); - } - } - } - } - private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) { if (keyEvent == null) { return false; @@ -1113,85 +1074,6 @@ public class MediaFocusControl implements OnFinished { /** * Helper function: - * Remove any entry in the remote control stack that has the same package name as packageName - * Pre-condition: packageName != null - */ - private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) { - synchronized(mPRStack) { - if (mPRStack.empty()) { - return; - } else { - final PackageManager pm = mContext.getPackageManager(); - PlayerRecord oldTop = mPRStack.peek(); - Iterator<PlayerRecord> stackIterator = mPRStack.iterator(); - // iterate over the stack entries - // (using an iterator on the stack so we can safely remove an entry after having - // evaluated it, traversal order doesn't matter here) - while(stackIterator.hasNext()) { - PlayerRecord prse = stackIterator.next(); - if (removeAll - && packageName.equals(prse.getMediaButtonIntent().getCreatorPackage())) - { - // a stack entry is from the package being removed, remove it from the stack - stackIterator.remove(); - prse.destroy(); - } else if (prse.getMediaButtonReceiver() != null) { - try { - // Check to see if this receiver still exists. - pm.getReceiverInfo(prse.getMediaButtonReceiver(), 0); - } catch (PackageManager.NameNotFoundException e) { - // Not found -- remove it! - stackIterator.remove(); - prse.destroy(); - } - } - } - if (mPRStack.empty()) { - // no saved media button receiver - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, - null)); - } else if (oldTop != mPRStack.peek()) { - // the top of the stack has changed, save it in the system settings - // by posting a message to persist it; only do this however if it has - // a concrete component name (is not a transient registration) - PlayerRecord prse = mPRStack.peek(); - if (prse.getMediaButtonReceiver() != null) { - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, - prse.getMediaButtonReceiver())); - } - } - } - } - } - - /** - * Helper function: - * Restore remote control receiver from the system settings. - */ - protected void restoreMediaButtonReceiver() { - String receiverName = Settings.System.getStringForUser(mContentResolver, - Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT); - if ((null != receiverName) && !receiverName.isEmpty()) { - ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); - if (eventReceiver == null) { - // an invalid name was persisted - return; - } - // construct a PendingIntent targeted to the restored component name - // for the media button and register it - Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); - // the associated intent will be handled by the component being registered - mediaButtonIntent.setComponent(eventReceiver); - PendingIntent pi = PendingIntent.getBroadcast(mContext, - 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); - registerMediaButtonIntent(pi, eventReceiver, null /*token*/); - } - } - - /** - * Helper function: * Push the new media button receiver "near" the top of the PlayerRecord stack. * "Near the top" is defined as: * - at the top if the current PlayerRecord at the top is not playing @@ -1258,13 +1140,6 @@ public class MediaFocusControl implements OnFinished { } } - topChanged = (oldTopPrse != mPRStack.lastElement()); - // post message to persist the default media button receiver - if (topChanged && (target != null)) { - mEventHandler.sendMessage( mEventHandler.obtainMessage( - MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) ); - } - } catch (ArrayIndexOutOfBoundsException e) { // not expected to happen, indicates improper concurrent modification or bad index Log.e(TAG, "Wrong index (inStack=" + inStackIndex + " lastPlaying=" + lastPlayingIndex @@ -1309,13 +1184,6 @@ public class MediaFocusControl implements OnFinished { return false; } - private void onHandlePersistMediaButtonReceiver(ComponentName receiver) { - Settings.System.putStringForUser(mContentResolver, - Settings.System.MEDIA_BUTTON_RECEIVER, - receiver == null ? "" : receiver.flattenToString(), - UserHandle.USER_CURRENT); - } - //========================================================================================== // Remote control display / client //========================================================================================== diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index a95348f69140..a1ccf6011043 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -43,7 +43,8 @@ import java.util.Map; * <tr><td>{@link #KEY_COLOR_FORMAT}</td><td>Integer</td><td>set by the user * for encoders, readable in the output format of decoders</b></td></tr> * <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr> - * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr> + * <tr><td>{@link #KEY_CAPTURE_RATE}</td><td>Integer</td><td></td></tr> +* <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr> * <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr> * <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr> * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>video encoder in surface-mode only</b></td></tr> @@ -206,6 +207,21 @@ public final class MediaFormat { public static final String KEY_FRAME_RATE = "frame-rate"; /** + * A key describing the capture rate of a video format in frames/sec. + * <p> + * When capture rate is different than the frame rate, it means that the + * video is acquired at a different rate than the playback, which produces + * slow motion or timelapse effect during playback. Application can use the + * value of this key to tell the relative speed ratio between capture and + * playback rates when the video was recorded. + * </p> + * <p> + * The associated value is an integer or a float. + * </p> + */ + public static final String KEY_CAPTURE_RATE = "capture-rate"; + + /** * A key describing the frequency of I frames expressed in secs * between I frames. * The associated value is an integer. diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java index 5d2f3bd58870..3f7ebce89170 100644 --- a/media/java/android/media/MediaMetadata.java +++ b/media/java/android/media/MediaMetadata.java @@ -19,6 +19,7 @@ import android.graphics.Bitmap; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.text.format.Time; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; @@ -73,7 +74,8 @@ public final class MediaMetadata implements Parcelable { public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION"; /** - * The date the media was created or published as TODO determine format. + * The date the media was created or published. The format is unspecified + * but RFC 3339 is recommended. */ public static final String METADATA_KEY_DATE = "android.media.metadata.DATE"; diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 59307d01f932..a77bb96266b3 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -160,10 +160,15 @@ public class MediaRecorder * {@link MediaRecorder#setAudioSource(int)}. */ public final class AudioSource { + + private AudioSource() {} + + /** @hide */ + public final static int AUDIO_SOURCE_INVALID = -1; + /* Do not change these values without updating their counterparts * in system/core/include/system/audio.h! */ - private AudioSource() {} /** Default audio source **/ public static final int DEFAULT = 0; diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java index 75a89528374d..0aaaf46bebd9 100644 --- a/media/java/android/media/RemoteController.java +++ b/media/java/android/media/RemoteController.java @@ -74,8 +74,7 @@ import java.util.List; private MetadataEditor mMetadataEditor; private MediaSessionManager mSessionManager; - private MediaSessionManager.SessionListener mSessionListener - = new TopTransportSessionListener(); + private MediaSessionManager.SessionListener mSessionListener; private MediaController.Callback mSessionCb = new MediaControllerCallback(); /** @@ -141,6 +140,7 @@ import java.util.List; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mSessionManager = (MediaSessionManager) context .getSystemService(Context.MEDIA_SESSION_SERVICE); + mSessionListener = new TopTransportSessionListener(context); if (ActivityManager.isLowRamDeviceStatic()) { mMaxBitmapDimension = MAX_BITMAP_DIMENSION; @@ -214,7 +214,7 @@ import java.util.List; public String getRemoteControlClientPackageName() { if (USE_SESSIONS) { synchronized (mInfoLock) { - return mCurrentSession != null ? mCurrentSession.getSessionInfo().getPackageName() + return mCurrentSession != null ? mCurrentSession.getPackageName() : null; } } else { @@ -711,6 +711,11 @@ import java.util.List; * currently tracked session if it has changed. */ private class TopTransportSessionListener extends MediaSessionManager.SessionListener { + + public TopTransportSessionListener(Context context) { + super(context); + } + @Override public void onActiveSessionsChanged(List<MediaController> controllers) { int size = controllers.size(); @@ -980,8 +985,8 @@ import java.util.List; 0 /* genId */, 1 /* clearing */, null /* obj */, 0 /* delay */); } } else if (mCurrentSession == null - || !controller.getSessionInfo().getId() - .equals(mCurrentSession.getSessionInfo().getId())) { + || !controller.getSessionToken() + .equals(mCurrentSession.getSessionToken())) { if (mCurrentSession != null) { mCurrentSession.removeCallback(mSessionCb); } diff --git a/media/java/android/media/browse/IMediaBrowserService.aidl b/media/java/android/media/browse/IMediaBrowserService.aidl index 177bd1bbc5de..8acd724892fc 100644 --- a/media/java/android/media/browse/IMediaBrowserService.aidl +++ b/media/java/android/media/browse/IMediaBrowserService.aidl @@ -18,5 +18,6 @@ oneway interface IMediaBrowserService { void addSubscription(in Uri uri, IMediaBrowserServiceCallbacks callbacks); void removeSubscription(in Uri uri, IMediaBrowserServiceCallbacks callbacks); - void loadThumbnail(in Uri uri, int width, int height, IMediaBrowserServiceCallbacks callbacks); + void loadIcon(in int seqNum, in Uri uri, int width, int height, + IMediaBrowserServiceCallbacks callbacks); }
\ No newline at end of file diff --git a/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl b/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl index 1f03a1a84b2e..06fabcc810b6 100644 --- a/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl +++ b/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl @@ -24,5 +24,5 @@ oneway interface IMediaBrowserServiceCallbacks { void onConnect(in Uri root, in MediaSession.Token session, in Bundle extras); void onConnectFailed(); void onLoadChildren(in Uri uri, in ParceledListSlice list); - void onLoadThumbnail(in Uri uri, int width, int height, in Bitmap bitmap); + void onLoadIcon(int seqNum, in Bitmap bitmap); } diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index d17f95d6c5f4..858383eee205 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -33,6 +33,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; +import android.util.SparseArray; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -40,6 +41,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -65,8 +67,8 @@ public final class MediaBrowser { private final Handler mHandler = new Handler(); private final ArrayMap<Uri,Subscription> mSubscriptions = new ArrayMap<Uri, MediaBrowser.Subscription>(); - private final ArrayMap<ThumbnailRequest, HashSet<ThumbnailCallback>> mThumbnailCallbacks = - new ArrayMap<ThumbnailRequest, HashSet<ThumbnailCallback>>(); + private final SparseArray<IconRequest> mIconRequests = + new SparseArray<IconRequest>(); private int mState = CONNECT_STATE_DISCONNECTED; private MediaServiceConnection mServiceConnection; @@ -75,6 +77,7 @@ public final class MediaBrowser { private Uri mRootUri; private MediaSession.Token mMediaSessionToken; private Bundle mExtras; + private int mNextSeq; /** * Creates a media browser for the specified media browse service. @@ -349,43 +352,42 @@ public final class MediaBrowser { } /** - * Loads the thumbnail of a media item. + * Loads the icon of a media item. * - * @param uri The uri of the thumbnail. + * @param uri The uri of the Icon. * @param width The preferred width of the icon in dp. * @param height The preferred width of the icon in dp. - * @param callback The callback to receive the thumbnail. + * @param callback The callback to receive the icon. */ - public void loadThumbnail(final @NonNull Uri uri, final int width, final int height, - final @NonNull ThumbnailCallback callback) { + public void loadIcon(final @NonNull Uri uri, final int width, final int height, + final @NonNull IconCallback callback) { if (uri == null) { - throw new IllegalArgumentException("thumbnail uri cannot be null"); + throw new IllegalArgumentException("Icon uri cannot be null"); } if (callback == null) { - throw new IllegalArgumentException("thumbnail callback cannot be null"); + throw new IllegalArgumentException("Icon callback cannot be null"); } mHandler.post(new Runnable() { @Override public void run() { - HashSet<ThumbnailCallback> callbackSet; - ThumbnailRequest request = new ThumbnailRequest(uri, width, height); - callbackSet = mThumbnailCallbacks.get(request); - if (callbackSet != null) { - callbackSet.add(callback); - mThumbnailCallbacks.put(request, callbackSet); - // same request has been sent. we will wait for the callback. - return; + for (int i = 0; i < mIconRequests.size(); i++) { + IconRequest existingRequest = mIconRequests.valueAt(i); + if (existingRequest.isSameRequest(uri, width, height)) { + existingRequest.addCallback(callback); + return; + } } - callbackSet = new HashSet<ThumbnailCallback>(); - callbackSet.add(callback); - mThumbnailCallbacks.put(request, callbackSet); + final int seq = mNextSeq++; + IconRequest request = new IconRequest(seq, uri, width, height); + request.addCallback(callback); + mIconRequests.put(seq, request); if (mState == CONNECT_STATE_CONNECTED) { try { - mServiceBinder.loadThumbnail(uri, width, height, mServiceCallbacks); + mServiceBinder.loadIcon(seq, uri, width, height, mServiceCallbacks); } catch (RemoteException e) { // Process is crashing. We will disconnect, and upon reconnect we will - // automatically reload the thumbnails. So nothing to do here. - Log.d(TAG, "loadThumbnail failed with RemoteException uri=" + uri); + // automatically reload the icons. So nothing to do here. + Log.d(TAG, "loadIcon failed with RemoteException uri=" + uri); } } } @@ -449,17 +451,17 @@ public final class MediaBrowser { } } - for (ThumbnailRequest request : mThumbnailCallbacks.keySet()) { + for (int i = 0; i < mIconRequests.size(); i++) { + IconRequest request = mIconRequests.valueAt(i); try { - mServiceBinder.loadThumbnail(request.uri, request.width, request.height, - mServiceCallbacks); + mServiceBinder.loadIcon(request.mSeq, request.mUri, + request.mWidth, request.mHeight, mServiceCallbacks); } catch (RemoteException e) { // Process is crashing. We will disconnect, and upon reconnect we will // automatically reload. So nothing to do here. - Log.d(TAG, "loadThumbnail failed with RemoteException uri=" + request.uri); + Log.d(TAG, "loadIcon failed with RemoteException request=" + request); } } - } }); } @@ -526,27 +528,27 @@ public final class MediaBrowser { }); } - private final void onLoadThumbnail(final IMediaBrowserServiceCallbacks callback, - final ThumbnailRequest request, final Bitmap bitmap) { + private final void onLoadIcon(final IMediaBrowserServiceCallbacks callback, + final int seqNum, final Bitmap bitmap) { mHandler.post(new Runnable() { @Override public void run() { // Check that there hasn't been a disconnect or a different // ServiceConnection. - if (!isCurrent(callback, "onLoadThumbnail")) { + if (!isCurrent(callback, "onLoadIcon")) { return; } - Set<ThumbnailCallback> callbackSet = mThumbnailCallbacks.get(request); - if (callbackSet == null) { - Log.d(TAG, "onLoadThumbnail called for request=" + request + - " but the callback is not registered"); + IconRequest request = mIconRequests.get(seqNum); + if (request == null) { + Log.d(TAG, "onLoadIcon called for seqNum=" + seqNum + " request=" + + request + " but the request is not registered"); return; } - for (ThumbnailCallback thumbnailCallback : callbackSet) { - thumbnailCallback.onThumbnailLoaded(request.uri, bitmap); + mIconRequests.delete(seqNum); + for (IconCallback IconCallback : request.getCallbacks()) { + IconCallback.onIconLoaded(request.mUri, bitmap); } - mThumbnailCallbacks.remove(request); } }); } @@ -634,13 +636,13 @@ public final class MediaBrowser { } /** - * Callbacks for thumbnail loading. + * Callbacks for icon loading. */ - public static abstract class ThumbnailCallback { + public static abstract class IconCallback { /** - * Called when the thumbnail is loaded. + * Called when the icon is loaded. */ - public void onThumbnailLoaded(@NonNull Uri uri, @NonNull Bitmap bitmap) { + public void onIconLoaded(@NonNull Uri uri, @NonNull Bitmap bitmap) { } /** @@ -650,48 +652,67 @@ public final class MediaBrowser { } } - private static class ThumbnailRequest { - Uri uri; - int width; - int height; - ThumbnailRequest(@NonNull Uri uri, int width, int height) { + private static class IconRequest { + final int mSeq; + final Uri mUri; + final int mWidth; + final int mHeight; + final List<IconCallback> mCallbacks; + + /** + * Constructs an icon request. + * @param seq The unique sequence number assigned to the request by the media browser. + * @param uri The Uri for the icon. + * @param width The width for the icon. + * @param height The height for the icon. + */ + IconRequest(int seq, @NonNull Uri uri, int width, int height) { if (uri == null) { - throw new IllegalArgumentException("thumbnail uri cannot be null"); + throw new IllegalArgumentException("Icon uri cannot be null"); } - this.uri = uri; - this.width = width; - this.height = height; + this.mSeq = seq; + this.mUri = uri; + this.mWidth = width; + this.mHeight = height; + mCallbacks = new ArrayList<IconCallback>(); } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ThumbnailRequest)) return false; - - ThumbnailRequest that = (ThumbnailRequest) o; - - if (height != that.height) return false; - if (width != that.width) return false; - if (!uri.equals(that.uri)) return false; - - return true; + /** + * Adds a callback to the icon request. + * If the callback already exists, it will not be added again. + */ + public void addCallback(@NonNull IconCallback callback) { + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null in IconRequest"); + } + if (!mCallbacks.contains(callback)) { + mCallbacks.add(callback); + } } - @Override - public int hashCode() { - int result = uri.hashCode(); - result = 31 * result + width; - result = 31 * result + height; - return result; + /** + * Checks if the icon request has the same uri, width, and height as the given values. + */ + public boolean isSameRequest(@Nullable Uri uri, int width, int height) { + return Objects.equals(mUri, uri) && mWidth == width && mHeight == height; } @Override public String toString() { - return "ThumbnailRequest{" + - "uri=" + uri + - ", width=" + width + - ", height=" + height + - '}'; + final StringBuilder sb = new StringBuilder("IconRequest{"); + sb.append("uri=").append(mUri); + sb.append(", width=").append(mWidth); + sb.append(", height=").append(mHeight); + sb.append(", seq=").append(mSeq); + sb.append('}'); + return sb.toString(); + } + + /** + * Gets an unmodifiable view of the list of callbacks associated with the request. + */ + public List<IconCallback> getCallbacks() { + return Collections.unmodifiableList(mCallbacks); } } @@ -822,11 +843,10 @@ public final class MediaBrowser { } @Override - public void onLoadThumbnail(final Uri uri, int width, int height, final Bitmap bitmap) { + public void onLoadIcon(final int seqNum, final Bitmap bitmap) { MediaBrowser mediaBrowser = mMediaBrowser.get(); if (mediaBrowser != null) { - ThumbnailRequest request = new ThumbnailRequest(uri, width, height); - mediaBrowser.onLoadThumbnail(this, request, bitmap); + mediaBrowser.onLoadIcon(this, seqNum, bitmap); } } } diff --git a/media/java/android/media/browse/MediaBrowserService.java b/media/java/android/media/browse/MediaBrowserService.java index 2d4bb7830aa6..99126c98b87a 100644 --- a/media/java/android/media/browse/MediaBrowserService.java +++ b/media/java/android/media/browse/MediaBrowserService.java @@ -105,7 +105,7 @@ public abstract class MediaBrowserService extends Service { * be thrown. * * @see MediaBrowserService#onLoadChildren - * @see MediaBrowserService#onLoadThumbnail + * @see MediaBrowserService#onLoadIcon */ public class Result<T> { private Object mDebug; @@ -266,10 +266,10 @@ public abstract class MediaBrowserService extends Service { } @Override - public void loadThumbnail(final Uri uri, final int width, final int height, + public void loadIcon(final int seq, final Uri uri, final int width, final int height, final IMediaBrowserServiceCallbacks callbacks) { if (uri == null) { - throw new IllegalStateException("loadThumbnail sent null list for uri " + uri); + throw new IllegalStateException("loadIcon sent null list for uri " + uri); } mHandler.post(new Runnable() { @Override @@ -291,7 +291,7 @@ public abstract class MediaBrowserService extends Service { void onResultSent(Bitmap bitmap) { if (mConnections.get(connection.callbacks.asBinder()) != connection) { if (DBG) { - Log.d(TAG, "Not sending onLoadThumbnail result for connection" + Log.d(TAG, "Not sending onLoadIcon result for connection" + " that has been disconnected. pkg=" + connection.pkg + " uri=" + uri); } @@ -299,18 +299,18 @@ public abstract class MediaBrowserService extends Service { } try { - callbacks.onLoadThumbnail(uri, width, height, bitmap); + callbacks.onLoadIcon(seq, bitmap); } catch (RemoteException e) { // The other side is in the process of crashing. - Log.w(TAG, "RemoteException in calling onLoadThumbnail", e); + Log.w(TAG, "RemoteException in calling onLoadIcon", e); } } }; - onLoadThumbnail(uri, width, height, result); + onLoadIcon(uri, width, height, result); if (!result.isDone()) { - throw new IllegalStateException("onLoadThumbnail must call detach() or" + throw new IllegalStateException("onLoadIcon must call detach() or" + " sendResult() before returning for package=" + connection.pkg + " uri=" + uri); } @@ -371,11 +371,11 @@ public abstract class MediaBrowserService extends Service { * children are to be queried. * @return The list of children, or null if the uri is invalid. */ - protected abstract void onLoadChildren(@NonNull Uri parentUri, + public abstract void onLoadChildren(@NonNull Uri parentUri, @NonNull Result<List<MediaBrowserItem>> result); /** - * Called to get the thumbnail of a particular media item. + * Called to get the icon of a particular media item. * <p> * Implementations must call result.{@link Result#sendResult result.sendResult} with the bitmap. * If loading the bitmap will be an expensive operation that should be performed @@ -387,10 +387,10 @@ public abstract class MediaBrowserService extends Service { * @param width The requested width of the icon in dp. * @param height The requested height of the icon in dp. * - * @return The file descriptor of the thumbnail, which may then be loaded - * using a bitmap factory, or null if the item does not have a thumbnail. + * @return The file descriptor of the icon, which may then be loaded + * using a bitmap factory, or null if the item does not have an icon. */ - protected abstract void onLoadThumbnail(@NonNull Uri uri, int width, int height, + public abstract void onLoadIcon(@NonNull Uri uri, int width, int height, @NonNull Result<Bitmap> result); /** diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl index 2c190b788488..af3b72e7f49f 100644 --- a/media/java/android/media/session/ISession.aidl +++ b/media/java/android/media/session/ISession.aidl @@ -15,7 +15,7 @@ package android.media.session; -import android.content.ComponentName; +import android.app.PendingIntent; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; import android.media.MediaMetadata; @@ -36,7 +36,8 @@ interface ISession { void setFlags(int flags); void setActive(boolean active); void setMediaRouter(in IMediaRouter router); - void setMediaButtonReceiver(in ComponentName mbr); + void setMediaButtonReceiver(in PendingIntent mbr); + void setLaunchPendingIntent(in PendingIntent pi); void destroy(); // These commands are for the TransportPerformer diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index d20b0ad505ee..3518458fe706 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -15,6 +15,7 @@ package android.media.session; +import android.app.PendingIntent; import android.content.Intent; import android.content.pm.ParceledListSlice; import android.media.MediaMetadata; @@ -22,7 +23,6 @@ import android.media.Rating; import android.media.routing.IMediaRouterDelegate; import android.media.routing.IMediaRouterStateCallback; import android.media.session.ISessionControllerCallback; -import android.media.session.MediaSessionInfo; import android.media.session.ParcelableVolumeInfo; import android.media.session.PlaybackState; import android.media.session.MediaSession; @@ -43,7 +43,9 @@ interface ISessionController { void registerCallbackListener(in ISessionControllerCallback cb); void unregisterCallbackListener(in ISessionControllerCallback cb); boolean isTransportControlEnabled(); - MediaSessionInfo getSessionInfo(); + String getPackageName(); + String getTag(); + PendingIntent getLaunchPendingIntent(); long getFlags(); ParcelableVolumeInfo getVolumeAttributes(); void adjustVolume(int direction, int flags); diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 050db211411a..382579c7eff4 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -18,6 +18,8 @@ package android.media.session; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.PendingIntent; +import android.content.Context; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; import android.media.AudioManager; @@ -64,12 +66,15 @@ public final class MediaController { private final ISessionController mSessionBinder; + private final MediaSession.Token mToken; + private final Context mContext; private final CallbackStub mCbStub = new CallbackStub(this); private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); private final Object mLock = new Object(); private boolean mCbRegistered = false; - private MediaSessionInfo mInfo; + private String mPackageName; + private String mTag; private final TransportControls mTransportControls; @@ -79,21 +84,27 @@ public final class MediaController { * * @hide */ - public MediaController(ISessionController sessionBinder) { + public MediaController(Context context, ISessionController sessionBinder) { if (sessionBinder == null) { throw new IllegalArgumentException("Session token cannot be null"); } + if (context == null) { + throw new IllegalArgumentException("Context cannot be null"); + } mSessionBinder = sessionBinder; mTransportControls = new TransportControls(); + mToken = new MediaSession.Token(sessionBinder); + mContext = context; } /** * Create a new MediaController from a session's token. * + * @param context The caller's context. * @param token The token for the session. */ - public MediaController(@NonNull MediaSession.Token token) { - this(token.getBinder()); + public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) { + this(context, token.getBinder()); } /** @@ -208,12 +219,11 @@ public final class MediaController { } /** - * Get the flags for this session. + * Get the flags for this session. Flags are defined in {@link MediaSession}. * * @return The current set of flags for the session. - * @hide */ - public long getFlags() { + public @MediaSession.SessionFlags long getFlags() { try { return mSessionBinder.getFlags(); } catch (RemoteException e) { @@ -240,6 +250,30 @@ public final class MediaController { } /** + * Get an intent for launching UI associated with this session if one + * exists. + * + * @return A {@link PendingIntent} to launch UI or null. + */ + public @Nullable PendingIntent getLaunchActivity() { + try { + return mSessionBinder.getLaunchPendingIntent(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling getPendingIntent.", e); + } + return null; + } + + /** + * Get the token for the session this is connected to. + * + * @return The token for the connected session. + */ + public @NonNull MediaSession.Token getSessionToken() { + return mToken; + } + + /** * Set the volume of the output this session is playing on. The command will * be ignored if it does not support * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in @@ -345,20 +379,36 @@ public final class MediaController { } /** - * Get the info for the session this controller is connected to. + * Get the session owner's package name. + * + * @return The package name of of the session owner. + */ + public String getPackageName() { + if (mPackageName == null) { + try { + mPackageName = mSessionBinder.getPackageName(); + } catch (RemoteException e) { + Log.d(TAG, "Dead object in getPackageName.", e); + } + } + return mPackageName; + } + + /** + * Get the session's tag for debugging purposes. * - * @return The session info for the connected session. + * @return The session's tag. * @hide */ - public MediaSessionInfo getSessionInfo() { - if (mInfo == null) { + public String getTag() { + if (mTag == null) { try { - mInfo = mSessionBinder.getSessionInfo(); + mTag = mSessionBinder.getTag(); } catch (RemoteException e) { - Log.e(TAG, "Error in getSessionInfo.", e); + Log.d(TAG, "Dead object in getTag.", e); } } - return mInfo; + return mTag; } /* diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index be2d479c0231..cf8e3ddd1239 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -16,8 +16,10 @@ package android.media.session; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.Activity; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; @@ -42,6 +44,8 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -95,6 +99,14 @@ public final class MediaSession { */ public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = { + FLAG_HANDLES_MEDIA_BUTTONS, + FLAG_HANDLES_TRANSPORT_CONTROLS, + FLAG_EXCLUSIVE_GLOBAL_PRIORITY }) + public @interface SessionFlags { } + /** * The session uses local playback. */ @@ -108,6 +120,7 @@ public final class MediaSession { private final Object mLock = new Object(); private final MediaSession.Token mSessionToken; + private final MediaController mController; private final ISession mBinder; private final CallbackStub mCbStub; @@ -157,6 +170,7 @@ public final class MediaSession { try { mBinder = manager.createSession(mCbStub, tag, userId); mSessionToken = new Token(mBinder.getController()); + mController = new MediaController(context, mSessionToken); } catch (RemoteException e) { throw new RuntimeException("Remote error creating session.", e); } @@ -211,12 +225,17 @@ public final class MediaSession { /** * Set an intent for launching UI for this Session. This can be used as a - * quick link to an ongoing media screen. + * quick link to an ongoing media screen. The intent should be for an + * activity that may be started using {@link Activity#startActivity(Intent)}. * * @param pi The intent to launch to show UI for this Session. */ - public void setLaunchPendingIntent(@Nullable PendingIntent pi) { - // TODO + public void setLaunchActivity(@Nullable PendingIntent pi) { + try { + mBinder.setLaunchPendingIntent(pi); + } catch (RemoteException e) { + Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e); + } } /** @@ -237,13 +256,14 @@ public final class MediaSession { } /** - * Set a media button event receiver component to use to restart playback - * after an app has been stopped. + * Set a pending intent for your media button receiver to allow restarting + * playback after the session has been stopped. If your app is started in + * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via + * the pending intent. * - * @param mbr The receiver component to send the media button event to. - * @hide + * @param mbr The {@link PendingIntent} to send the media button event to. */ - public void setMediaButtonReceiver(@Nullable ComponentName mbr) { + public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { try { mBinder.setMediaButtonReceiver(mbr); } catch (RemoteException e) { @@ -256,7 +276,7 @@ public final class MediaSession { * * @param flags The flags to set for this session. */ - public void setFlags(int flags) { + public void setFlags(@SessionFlags int flags) { try { mBinder.setFlags(flags); } catch (RemoteException e) { @@ -391,6 +411,16 @@ public final class MediaSession { } /** + * Get a controller for this session. This is a convenience method to avoid + * having to cache your own controller in process. + * + * @return A controller for this session. + */ + public @NonNull MediaController getController() { + return mController; + } + + /** * Add a callback to receive transport controls on, such as play, rewind, or * fast forward. * @@ -697,6 +727,7 @@ public final class MediaSession { * the session. */ public static final class Token implements Parcelable { + private ISessionController mBinder; /** @@ -716,6 +747,31 @@ public final class MediaSession { dest.writeStrongBinder(mBinder.asBinder()); } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Token other = (Token) obj; + if (mBinder == null) { + if (other.mBinder != null) + return false; + } else if (!mBinder.asBinder().equals(other.mBinder.asBinder())) + return false; + return true; + } + ISessionController getBinder() { return mBinder; } diff --git a/media/java/android/media/session/MediaSessionInfo.aidl b/media/java/android/media/session/MediaSessionInfo.aidl deleted file mode 100644 index 63dca9a102b0..000000000000 --- a/media/java/android/media/session/MediaSessionInfo.aidl +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 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 android.media.session; - -parcelable MediaSessionInfo; diff --git a/media/java/android/media/session/MediaSessionInfo.java b/media/java/android/media/session/MediaSessionInfo.java deleted file mode 100644 index 4dc1c09b6aee..000000000000 --- a/media/java/android/media/session/MediaSessionInfo.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 android.media.session; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Information about a media session, including the owner's package name. - * - * @hide - */ -public final class MediaSessionInfo implements Parcelable { - private final String mId; - private final String mPackageName; - private final int mPid; - - /** - * @hide - */ - public MediaSessionInfo(String id, String packageName, int pid) { - mId = id; - mPackageName = packageName; - mPid = pid; - } - - private MediaSessionInfo(Parcel in) { - mId = in.readString(); - mPackageName = in.readString(); - mPid = in.readInt(); - } - - /** - * Get the package name of the owner of this session. - * - * @return The owner's package name - */ - public String getPackageName() { - return mPackageName; - } - - /** - * Get the unique id for this session. - * - * @return The id for the session. - */ - public String getId() { - return mId; - } - - public int getPid() { - return mPid; - } - - @Override - public String toString() { - return "SessionInfo {id=" + mId + ", pkg=" + mPackageName + ", pid=" + mPid + "}"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mId); - dest.writeString(mPackageName); - dest.writeInt(mPid); - } - - public static final Parcelable.Creator<MediaSessionInfo> CREATOR - = new Parcelable.Creator<MediaSessionInfo>() { - @Override - public MediaSessionInfo createFromParcel(Parcel in) { - return new MediaSessionInfo(in); - } - - @Override - public MediaSessionInfo[] newArray(int size) { - return new MediaSessionInfo[size]; - } - }; -} diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java index a6963cfe98af..f075ded90f45 100644 --- a/media/java/android/media/session/MediaSessionLegacyHelper.java +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -304,7 +304,7 @@ public class MediaSessionLegacyHelper { holder.mMediaButtonReceiver = new MediaButtonReceiver(pi, context); holder.mSession.addCallback(holder.mMediaButtonReceiver, mHandler); - holder.mSession.setMediaButtonReceiver(mbrComponent); + holder.mSession.setMediaButtonReceiver(pi); if (DEBUG) { Log.d(TAG, "addMediaButtonListener added " + pi); } @@ -369,7 +369,7 @@ public class MediaSessionLegacyHelper { SessionHolder holder = mSessions.get(pi); if (holder == null && createIfMissing) { MediaSession session; - session = new MediaSession(mContext, TAG); + session = new MediaSession(mContext, TAG + "-" + pi.getCreatorPackage()); session.setActive(true); holder = new SessionHolder(session, pi); mSessions.put(pi, holder); diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index 824b39708d49..84983b91a36a 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -116,7 +116,7 @@ public final class MediaSessionManager { List<IBinder> binders = mService.getSessions(notificationListener, userId); int size = binders.size(); for (int i = 0; i < size; i++) { - MediaController controller = new MediaController(ISessionController.Stub + MediaController controller = new MediaController(mContext, ISessionController.Stub .asInterface(binders.get(i))); controllers.add(controller); } @@ -175,7 +175,6 @@ public final class MediaSessionManager { * Stop receiving active sessions updates on the specified listener. * * @param listener The listener to remove. - * @hide */ public void removeActiveSessionsListener(@NonNull SessionListener listener) { if (listener == null) { @@ -253,6 +252,11 @@ public final class MediaSessionManager { * using {@link #addActiveSessionsListener}. */ public static abstract class SessionListener { + private final Context mContext; + + public SessionListener(Context context) { + mContext = context; + } /** * Called when the list of active sessions has changed. This can be due * to a session being added or removed or the order of sessions @@ -271,7 +275,7 @@ public final class MediaSessionManager { ArrayList<MediaController> controllers = new ArrayList<MediaController>(); int size = tokens.size(); for (int i = 0; i < size; i++) { - controllers.add(new MediaController(tokens.get(i))); + controllers.add(new MediaController(mContext, tokens.get(i))); } SessionListener.this.onActiveSessionsChanged(controllers); } diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java index 35a68a4ff296..9fb552c82730 100644 --- a/media/java/android/media/tv/ITvInputSessionWrapper.java +++ b/media/java/android/media/tv/ITvInputSessionWrapper.java @@ -147,7 +147,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand return; } case DO_REQUEST_UNBLOCK_CONTENT: { - mTvInputSessionImpl.requestUnblockContent((String) msg.obj); + mTvInputSessionImpl.unblockContent((String) msg.obj); return; } default: { diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index d2071ef07415..1a4305127421 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -696,19 +696,6 @@ public final class TvContract { public static final String COLUMN_SEARCHABLE = "searchable"; /** - * The flag indicating whether this TV channel is scrambled by conditional access or not. - * <p> - * This is used for indicating that this channel is protected by a conditional access - * system. A value of 1 indicates the channel is scrambled and the user is required - * to contact the service provider to watch this channel. A value of 0 indicates the channel - * is not scrambled. If not specified, this value is set to 0 (not scrambled) by default. - * </p><p> - * Type: INTEGER (boolean) - * </p> - */ - public static final String COLUMN_CONDITIONAL_ACCESS = "conditional_access"; - - /** * The flag indicating whether this TV channel is locked or not. * <p> * This is primarily used for alternative parental control to prevent unauthorized users diff --git a/media/java/android/media/tv/TvInputPassthroughWrapperService.java b/media/java/android/media/tv/TvInputPassthroughWrapperService.java index e99044d3abae..08c802f62da8 100644 --- a/media/java/android/media/tv/TvInputPassthroughWrapperService.java +++ b/media/java/android/media/tv/TvInputPassthroughWrapperService.java @@ -170,7 +170,7 @@ public abstract class TvInputPassthroughWrapperService extends TvInputService { public void onSessionEvent(TvInputManager.Session session, String eventType, Bundle eventArgs) { if (mSession == session) { - dispatchSessionEvent(eventType, eventArgs); + notifySessionEvent(eventType, eventArgs); } } }; @@ -188,13 +188,13 @@ public abstract class TvInputPassthroughWrapperService extends TvInputService { /** * Called when the underlying pass-through TV input session calls - * {@link #dispatchVideoAvailable()}. + * {@link #notifyVideoAvailable()}. */ public abstract void onPassthroughVideoAvailable(); /** * Called when the underlying pass-through TV input session calls - * {@link #dispatchVideoUnavailable(int)}. + * {@link #notifyVideoUnavailable(int)}. * * @param reason The reason why the pass-through TV input stopped the playback. */ diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index f41c6dd780dd..6b0a63345cea 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -282,7 +282,7 @@ public abstract class TvInputService extends Service { * @param eventArgs Optional arguments of the event. * @hide */ - public void dispatchSessionEvent(final String eventType, final Bundle eventArgs) { + public void notifySessionEvent(final String eventType, final Bundle eventArgs) { if (eventType == null) { throw new IllegalArgumentException("eventType should not be null."); } @@ -290,7 +290,7 @@ public abstract class TvInputService extends Service { @Override public void run() { try { - if (DEBUG) Log.d(TAG, "dispatchSessionEvent(" + eventType + ")"); + if (DEBUG) Log.d(TAG, "notifySessionEvent(" + eventType + ")"); mSessionCallback.onSessionEvent(eventType, eventArgs); } catch (RemoteException e) { Log.w(TAG, "error in sending event (event=" + eventType + ")"); @@ -304,15 +304,15 @@ public abstract class TvInputService extends Service { * * @param channelUri The URI of a channel. */ - public void dispatchChannelRetuned(final Uri channelUri) { + public void notifyChannelRetuned(final Uri channelUri) { mHandler.post(new Runnable() { @Override public void run() { try { - if (DEBUG) Log.d(TAG, "dispatchChannelRetuned"); + if (DEBUG) Log.d(TAG, "notifyChannelRetuned"); mSessionCallback.onChannelRetuned(channelUri); } catch (RemoteException e) { - Log.w(TAG, "error in dispatchChannelRetuned"); + Log.w(TAG, "error in notifyChannelRetuned"); } } }); @@ -324,7 +324,7 @@ public abstract class TvInputService extends Service { * * @param tracks A list which includes track information. */ - public void dispatchTrackInfoChanged(final List<TvTrackInfo> tracks) { + public void notifyTrackInfoChanged(final List<TvTrackInfo> tracks) { if (!TvTrackInfo.checkSanity(tracks)) { throw new IllegalArgumentException( "Two or more selected tracks for a track type."); @@ -333,10 +333,10 @@ public abstract class TvInputService extends Service { @Override public void run() { try { - if (DEBUG) Log.d(TAG, "dispatchTrackInfoChanged"); + if (DEBUG) Log.d(TAG, "notifyTrackInfoChanged"); mSessionCallback.onTrackInfoChanged(tracks); } catch (RemoteException e) { - Log.w(TAG, "error in dispatchTrackInfoChanged"); + Log.w(TAG, "error in notifyTrackInfoChanged"); } } }); @@ -346,15 +346,15 @@ public abstract class TvInputService extends Service { * Informs the application that video is available and the playback of the TV stream has * been started. */ - public void dispatchVideoAvailable() { + public void notifyVideoAvailable() { mHandler.post(new Runnable() { @Override public void run() { try { - if (DEBUG) Log.d(TAG, "dispatchVideoAvailable"); + if (DEBUG) Log.d(TAG, "notifyVideoAvailable"); mSessionCallback.onVideoAvailable(); } catch (RemoteException e) { - Log.w(TAG, "error in dispatchVideoAvailable"); + Log.w(TAG, "error in notifyVideoAvailable"); } } }); @@ -372,7 +372,7 @@ public abstract class TvInputService extends Service { * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING} * </ul> */ - public void dispatchVideoUnavailable(final int reason) { + public void notifyVideoUnavailable(final int reason) { if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START || reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) { throw new IllegalArgumentException("Unknown reason: " + reason); @@ -381,10 +381,10 @@ public abstract class TvInputService extends Service { @Override public void run() { try { - if (DEBUG) Log.d(TAG, "dispatchVideoUnavailable"); + if (DEBUG) Log.d(TAG, "notifyVideoUnavailable"); mSessionCallback.onVideoUnavailable(reason); } catch (RemoteException e) { - Log.w(TAG, "error in dispatchVideoUnavailable"); + Log.w(TAG, "error in notifyVideoUnavailable"); } } }); @@ -411,18 +411,18 @@ public abstract class TvInputService extends Service { * reevaluate the current program with the new parental control settings. * </p> * - * @see #dispatchContentBlocked + * @see #notifyContentBlocked * @see TvParentalControlManager */ - public void dispatchContentAllowed() { + public void notifyContentAllowed() { mHandler.post(new Runnable() { @Override public void run() { try { - if (DEBUG) Log.d(TAG, "dispatchContentAllowed"); + if (DEBUG) Log.d(TAG, "notifyContentAllowed"); mSessionCallback.onContentAllowed(); } catch (RemoteException e) { - Log.w(TAG, "error in dispatchContentAllowed"); + Log.w(TAG, "error in notifyContentAllowed"); } } }); @@ -451,18 +451,18 @@ public abstract class TvInputService extends Service { * </p> * * @param rating The content rating for the current TV program. - * @see #dispatchContentAllowed + * @see #notifyContentAllowed * @see TvParentalControlManager */ - public void dispatchContentBlocked(final TvContentRating rating) { + public void notifyContentBlocked(final TvContentRating rating) { mHandler.post(new Runnable() { @Override public void run() { try { - if (DEBUG) Log.d(TAG, "dispatchContentBlocked"); + if (DEBUG) Log.d(TAG, "notifyContentBlocked"); mSessionCallback.onContentBlocked(rating.flattenToString()); } catch (RemoteException e) { - Log.w(TAG, "error in dispatchContentBlocked"); + Log.w(TAG, "error in notifyContentBlocked"); } } }); @@ -529,8 +529,8 @@ public abstract class TvInputService extends Service { public abstract void onSetStreamVolume(float volume); /** - * Tunes to a given channel. When the video is available, {@link #dispatchVideoAvailable()} - * should be called. Also, {@link #dispatchVideoUnavailable(int)} should be called when the + * Tunes to a given channel. When the video is available, {@link #notifyVideoAvailable()} + * should be called. Also, {@link #notifyVideoUnavailable(int)} should be called when the * TV input cannot continue playing the given channel. * * @param channelUri The URI of the channel. @@ -562,7 +562,7 @@ public abstract class TvInputService extends Service { * * @param unblockedRating An unblocked content rating */ - public void onRequestUnblockContent(TvContentRating unblockedRating) { + public void onUnblockContent(TvContentRating unblockedRating) { } /** @@ -571,12 +571,12 @@ public abstract class TvInputService extends Service { * If it is called multiple times on the same type of track (ie. Video, Audio, Text), the * track selected previously should be unselected in the implementation of this method. * Also, if the select operation was successful, the implementation should call - * {@link #dispatchTrackInfoChanged(List)} to report the updated track information. + * {@link #notifyTrackInfoChanged(List)} to report the updated track information. * </p> * * @param track The track to be selected. * @return {@code true} if the select operation was successful, {@code false} otherwise. - * @see #dispatchTrackInfoChanged + * @see #notifyTrackInfoChanged * @see TvTrackInfo#KEY_IS_SELECTED */ public boolean onSelectTrack(TvTrackInfo track) { @@ -587,12 +587,12 @@ public abstract class TvInputService extends Service { * Unselects a given track. * <p> * If the unselect operation was successful, the implementation should call - * {@link #dispatchTrackInfoChanged(List)} to report the updated track information. + * {@link #notifyTrackInfoChanged(List)} to report the updated track information. * </p> * * @param track The track to be unselected. * @return {@code true} if the unselect operation was successful, {@code false} otherwise. - * @see #dispatchTrackInfoChanged + * @see #notifyTrackInfoChanged * @see TvTrackInfo#KEY_IS_SELECTED */ public boolean onUnselectTrack(TvTrackInfo track) { @@ -744,12 +744,12 @@ public abstract class TvInputService extends Service { * session. */ void release() { + removeOverlayView(true); onRelease(); if (mSurface != null) { mSurface.release(); mSurface = null; } - removeOverlayView(true); } /** @@ -821,10 +821,10 @@ public abstract class TvInputService extends Service { } /** - * Calls {@link #onRequestUnblockContent}. + * Calls {@link #onUnblockContent}. */ - void requestUnblockContent(String unblockedRating) { - onRequestUnblockContent(TvContentRating.unflattenFromString(unblockedRating)); + void unblockContent(String unblockedRating) { + onUnblockContent(TvContentRating.unflattenFromString(unblockedRating)); // TODO: Handle failure. } diff --git a/media/java/android/media/tv/TvStreamConfig.java b/media/java/android/media/tv/TvStreamConfig.java index 7f0c92f5c22a..243f864c3cd3 100644 --- a/media/java/android/media/tv/TvStreamConfig.java +++ b/media/java/android/media/tv/TvStreamConfig.java @@ -16,6 +16,7 @@ package android.media.tv; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -23,6 +24,7 @@ import android.util.Log; /** * @hide */ +@SystemApi public class TvStreamConfig implements Parcelable { static final String TAG = TvStreamConfig.class.getSimpleName(); @@ -154,4 +156,4 @@ public class TvStreamConfig implements Parcelable { return config; } } -}
\ No newline at end of file +} diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java index 5fe9955d140f..a5eef0a85656 100644 --- a/media/java/android/media/tv/TvView.java +++ b/media/java/android/media/tv/TvView.java @@ -258,7 +258,7 @@ public class TvView extends ViewGroup { * </p> * * @param unblockedRating A TvContentRating to unblock. - * @see TvInputService.Session#dispatchContentBlocked(TvContentRating) + * @see TvInputService.Session#notifyContentBlocked(TvContentRating) * @hide */ @SystemApi @@ -484,8 +484,8 @@ public class TvView extends ViewGroup { } @Override - public void setVisibility(int visibility) { - super.setVisibility(visibility); + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); mSurfaceView.setVisibility(visibility); if (visibility == View.VISIBLE) { createSessionOverlayView(); diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 35317e1c51e0..fa4439d56c38 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -420,8 +420,11 @@ static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* bu "Width is not multiple of 4 %d", buffer->width); LOG_ALWAYS_FATAL_IF(buffer->height % 2, "Height is not even %d", buffer->height); + LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8), + "stride (%d) should be at least %d", + buffer->stride, buffer->width * 10 / 8); pData = buffer->data; - dataSize = buffer->width * buffer->height * 10 / 8; + dataSize = buffer->stride * buffer->height; break; case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: @@ -535,12 +538,15 @@ static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buff rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16); break; case HAL_PIXEL_FORMAT_BLOB: - case HAL_PIXEL_FORMAT_RAW10: // Blob is used for JPEG data, RAW10 is used for 10-bit raw data, they are // single plane, row and pixel strides are 0. ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); rowStride = 0; break; + case HAL_PIXEL_FORMAT_RAW10: + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + rowStride = buffer->stride; + break; case HAL_PIXEL_FORMAT_Y8: ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); LOG_ALWAYS_FATAL_IF(buffer->stride % 16, diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 04ff098cdf4d..d033f76696f8 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -90,6 +90,8 @@ JMediaCodec::JMediaCodec( mClass = (jclass)env->NewGlobalRef(clazz); mObject = env->NewWeakGlobalRef(thiz); + cacheJavaObjects(env); + mLooper = new ALooper; mLooper->setName("MediaCodec_looper"); @@ -105,6 +107,45 @@ JMediaCodec::JMediaCodec( } } +void JMediaCodec::cacheJavaObjects(JNIEnv *env) { + jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer"); + mByteBufferClass = (jclass)env->NewGlobalRef(clazz); + CHECK(mByteBufferClass != NULL); + + ScopedLocalRef<jclass> byteOrderClass( + env, env->FindClass("java/nio/ByteOrder")); + CHECK(byteOrderClass.get() != NULL); + + jmethodID nativeOrderID = env->GetStaticMethodID( + byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); + CHECK(nativeOrderID != NULL); + + jobject nativeByteOrderObj = + env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); + mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj); + CHECK(mNativeByteOrderObj != NULL); + env->DeleteLocalRef(nativeByteOrderObj); + nativeByteOrderObj = NULL; + + mByteBufferOrderMethodID = env->GetMethodID( + mByteBufferClass, + "order", + "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); + CHECK(mByteBufferOrderMethodID != NULL); + + mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID( + mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); + CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL); + + mByteBufferPositionMethodID = env->GetMethodID( + mByteBufferClass, "position", "(I)Ljava/nio/Buffer;"); + CHECK(mByteBufferPositionMethodID != NULL); + + mByteBufferLimitMethodID = env->GetMethodID( + mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;"); + CHECK(mByteBufferLimitMethodID != NULL); +} + status_t JMediaCodec::initCheck() const { return mCodec != NULL ? OK : NO_INIT; } @@ -148,6 +189,19 @@ JMediaCodec::~JMediaCodec() { mObject = NULL; env->DeleteGlobalRef(mClass); mClass = NULL; + deleteJavaObjects(env); +} + +void JMediaCodec::deleteJavaObjects(JNIEnv *env) { + env->DeleteGlobalRef(mByteBufferClass); + mByteBufferClass = NULL; + env->DeleteGlobalRef(mNativeByteOrderObj); + mNativeByteOrderObj = NULL; + + mByteBufferOrderMethodID = NULL; + mByteBufferAsReadOnlyBufferMethodID = NULL; + mByteBufferPositionMethodID = NULL; + mByteBufferLimitMethodID = NULL; } status_t JMediaCodec::setCallback(jobject cb) { @@ -298,177 +352,89 @@ status_t JMediaCodec::getBuffers( return err; } - ScopedLocalRef<jclass> byteBufferClass( - env, env->FindClass("java/nio/ByteBuffer")); - - CHECK(byteBufferClass.get() != NULL); - - jmethodID orderID = env->GetMethodID( - byteBufferClass.get(), - "order", - "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); - - CHECK(orderID != NULL); - - jmethodID asReadOnlyBufferID = env->GetMethodID( - byteBufferClass.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); - - CHECK(asReadOnlyBufferID != NULL); - - ScopedLocalRef<jclass> byteOrderClass( - env, env->FindClass("java/nio/ByteOrder")); - - CHECK(byteOrderClass.get() != NULL); - - jmethodID nativeOrderID = env->GetStaticMethodID( - byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); - CHECK(nativeOrderID != NULL); - - jobject nativeByteOrderObj = - env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); - CHECK(nativeByteOrderObj != NULL); - *bufArray = (jobjectArray)env->NewObjectArray( - buffers.size(), byteBufferClass.get(), NULL); + buffers.size(), mByteBufferClass, NULL); if (*bufArray == NULL) { - env->DeleteLocalRef(nativeByteOrderObj); return NO_MEMORY; } for (size_t i = 0; i < buffers.size(); ++i) { const sp<ABuffer> &buffer = buffers.itemAt(i); - // if this is an ABuffer that doesn't actually hold any accessible memory, - // use a null ByteBuffer - if (buffer->base() == NULL) { - continue; + jobject byteBuffer = NULL; + err = createByteBufferFromABuffer( + env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer); + if (err != OK) { + return err; } - jobject byteBuffer = - env->NewDirectByteBuffer( - buffer->base(), - buffer->capacity()); - if (!input && byteBuffer != NULL) { - jobject readOnlyBuffer = env->CallObjectMethod( - byteBuffer, asReadOnlyBufferID); + if (byteBuffer != NULL) { + env->SetObjectArrayElement( + *bufArray, i, byteBuffer); + env->DeleteLocalRef(byteBuffer); - byteBuffer = readOnlyBuffer; + byteBuffer = NULL; } - if (byteBuffer == NULL) { - env->DeleteLocalRef(nativeByteOrderObj); - return NO_MEMORY; - } - jobject me = env->CallObjectMethod( - byteBuffer, orderID, nativeByteOrderObj); - env->DeleteLocalRef(me); - me = NULL; - - env->SetObjectArrayElement( - *bufArray, i, byteBuffer); - - env->DeleteLocalRef(byteBuffer); - byteBuffer = NULL; } - env->DeleteLocalRef(nativeByteOrderObj); - nativeByteOrderObj = NULL; - return OK; } -status_t JMediaCodec::getBuffer( - JNIEnv *env, bool input, size_t index, jobject *buf) const { - sp<ABuffer> buffer; - - status_t err = - input - ? mCodec->getInputBuffer(index, &buffer) - : mCodec->getOutputBuffer(index, &buffer); - - if (err != OK) { - return err; - } - - ScopedLocalRef<jclass> byteBufferClass( - env, env->FindClass("java/nio/ByteBuffer")); - - CHECK(byteBufferClass.get() != NULL); - - jmethodID orderID = env->GetMethodID( - byteBufferClass.get(), - "order", - "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); - - CHECK(orderID != NULL); - - jmethodID asReadOnlyBufferID = env->GetMethodID( - byteBufferClass.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); - - CHECK(asReadOnlyBufferID != NULL); - - jmethodID positionID = env->GetMethodID( - byteBufferClass.get(), "position", "(I)Ljava/nio/Buffer;"); - - CHECK(positionID != NULL); - - jmethodID limitID = env->GetMethodID( - byteBufferClass.get(), "limit", "(I)Ljava/nio/Buffer;"); - - CHECK(limitID != NULL); - - ScopedLocalRef<jclass> byteOrderClass( - env, env->FindClass("java/nio/ByteOrder")); - - CHECK(byteOrderClass.get() != NULL); - - jmethodID nativeOrderID = env->GetStaticMethodID( - byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); - CHECK(nativeOrderID != NULL); - - jobject nativeByteOrderObj = - env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); - CHECK(nativeByteOrderObj != NULL); - +// static +status_t JMediaCodec::createByteBufferFromABuffer( + JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer, + jobject *buf) const { // if this is an ABuffer that doesn't actually hold any accessible memory, // use a null ByteBuffer + *buf = NULL; if (buffer->base() == NULL) { - *buf = NULL; return OK; } jobject byteBuffer = - env->NewDirectByteBuffer( - buffer->base(), - buffer->capacity()); - if (!input && byteBuffer != NULL) { + env->NewDirectByteBuffer(buffer->base(), buffer->capacity()); + if (readOnly && byteBuffer != NULL) { jobject readOnlyBuffer = env->CallObjectMethod( - byteBuffer, asReadOnlyBufferID); + byteBuffer, mByteBufferAsReadOnlyBufferMethodID); env->DeleteLocalRef(byteBuffer); byteBuffer = readOnlyBuffer; } if (byteBuffer == NULL) { - env->DeleteLocalRef(nativeByteOrderObj); return NO_MEMORY; } jobject me = env->CallObjectMethod( - byteBuffer, orderID, nativeByteOrderObj); + byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj); env->DeleteLocalRef(me); me = env->CallObjectMethod( - byteBuffer, limitID, - input ? buffer->capacity() : (buffer->offset() + buffer->size())); + byteBuffer, mByteBufferLimitMethodID, + clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size())); env->DeleteLocalRef(me); me = env->CallObjectMethod( - byteBuffer, positionID, - input ? 0 : buffer->offset()); + byteBuffer, mByteBufferPositionMethodID, + clearBuffer ? 0 : buffer->offset()); env->DeleteLocalRef(me); me = NULL; - env->DeleteLocalRef(nativeByteOrderObj); - nativeByteOrderObj = NULL; - *buf = byteBuffer; return OK; } +status_t JMediaCodec::getBuffer( + JNIEnv *env, bool input, size_t index, jobject *buf) const { + sp<ABuffer> buffer; + + status_t err = + input + ? mCodec->getInputBuffer(index, &buffer) + : mCodec->getOutputBuffer(index, &buffer); + + if (err != OK) { + return err; + } + + return createByteBufferFromABuffer( + env, !input /* readOnly */, input /* clearBuffer */, buffer, buf); +} + status_t JMediaCodec::getImage( JNIEnv *env, bool input, size_t index, jobject *buf) const { sp<ABuffer> buffer; @@ -490,15 +456,80 @@ status_t JMediaCodec::getImage( } // check if buffer is an image - AString imageData; - if (!buffer->meta()->findString("image-data", &imageData)) { + sp<ABuffer> imageData; + if (!buffer->meta()->findBuffer("image-data", &imageData)) { + return OK; + } + + int64_t timestamp = 0; + if (!input && buffer->meta()->findInt64("timeUs", ×tamp)) { + timestamp *= 1000; // adjust to ns + } + + jobject byteBuffer = NULL; + err = createByteBufferFromABuffer( + env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer); + if (err != OK) { + return OK; + } + + jobject infoBuffer = NULL; + err = createByteBufferFromABuffer( + env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer); + if (err != OK) { + env->DeleteLocalRef(byteBuffer); + byteBuffer = NULL; return OK; } + jobject cropRect = NULL; + int32_t left, top, right, bottom; + if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) { + ScopedLocalRef<jclass> rectClazz( + env, env->FindClass("android/graphics/Rect")); + CHECK(rectClazz.get() != NULL); + + jmethodID rectConstructID = env->GetMethodID( + rectClazz.get(), "<init>", "(IIII)V"); + + cropRect = env->NewObject( + rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1); + } + + ScopedLocalRef<jclass> imageClazz( + env, env->FindClass("android/media/MediaCodec$MediaImage")); + CHECK(imageClazz.get() != NULL); + + jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>", + "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V"); + + *buf = env->NewObject(imageClazz.get(), imageConstructID, + byteBuffer, infoBuffer, + (jboolean)!input /* readOnly */, + (jlong)timestamp, + (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect); + + // if MediaImage creation fails, return null + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + *buf = NULL; + } + + if (cropRect != NULL) { + env->DeleteLocalRef(cropRect); + cropRect = NULL; + } + + env->DeleteLocalRef(byteBuffer); + byteBuffer = NULL; + + env->DeleteLocalRef(infoBuffer); + infoBuffer = NULL; + return OK; } - status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const { AString name; diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index dbccb0fcf88e..f84a16aad7a3 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -26,6 +26,7 @@ namespace android { +struct ABuffer; struct ALooper; struct AMessage; struct AString; @@ -121,11 +122,26 @@ private: jweak mObject; sp<Surface> mSurfaceTextureClient; + // java objects cached + jclass mByteBufferClass; + jobject mNativeByteOrderObj; + jmethodID mByteBufferOrderMethodID; + jmethodID mByteBufferPositionMethodID; + jmethodID mByteBufferLimitMethodID; + jmethodID mByteBufferAsReadOnlyBufferMethodID; + sp<ALooper> mLooper; sp<MediaCodec> mCodec; sp<AMessage> mCallbackNotification; + status_t createByteBufferFromABuffer( + JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer, + jobject *buf) const; + + void cacheJavaObjects(JNIEnv *env); + void deleteJavaObjects(JNIEnv *env); + DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec); }; diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp index 1e5c700e2c32..007fc1422f8d 100644 --- a/media/jni/android_media_MediaProfiles.cpp +++ b/media/jni/android_media_MediaProfiles.cpp @@ -166,7 +166,9 @@ static bool isCamcorderQualityKnown(int quality) return ((quality >= CAMCORDER_QUALITY_LIST_START && quality <= CAMCORDER_QUALITY_LIST_END) || (quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START && - quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END)); + quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END) || + (quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START && + quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END)); } static jobject diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png Binary files differindex 7c4c1a699d3b..54d76c139cdd 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png Binary files differindex 649985d4f98e..133024053c06 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png Binary files differindex 791bf6da7581..6369d181044b 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png Binary files differindex 6c32af17afd0..063009d0fc87 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png Binary files differdeleted file mode 100644 index 5bc4e05e2ac5..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_dark.png Binary files differnew file mode 100644 index 000000000000..bea0eec25d0c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_dark.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_light.png Binary files differnew file mode 100644 index 000000000000..c4c264e75e43 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_light.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png Binary files differdeleted file mode 100644 index ffb076c77266..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_dark.png Binary files differnew file mode 100644 index 000000000000..f7e59a57343a --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_dark.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_light.png Binary files differnew file mode 100644 index 000000000000..ae50d743ff9b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_light.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png Binary files differindex 179db33f3dcb..e4627277960f 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png Binary files differindex 8704a7859ef7..8ac89b6dd1b2 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png Binary files differdeleted file mode 100644 index 465838d1e27f..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png Binary files differnew file mode 100644 index 000000000000..3cbff217311e --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png Binary files differnew file mode 100644 index 000000000000..7c8b5400e0b9 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png Binary files differindex 434a6e6333ca..864417138606 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png Binary files differindex 940d185db023..0a3a9a6ae759 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png Binary files differindex 35cdc1fba4a0..d37d9bf3fef3 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png Binary files differindex 8f3b82c16768..7ad6c373479d 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png Binary files differindex a3df8936db0a..bb7e5848e3a4 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png Binary files differnew file mode 100644 index 000000000000..0f5159b11ce4 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png Binary files differindex 92225bad0929..b3e7192383ca 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png Binary files differindex 55b9b7d3c256..a799a83d4a49 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png Binary files differdeleted file mode 100644 index 72b611db3e64..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png Binary files differnew file mode 100644 index 000000000000..10c0b996bb77 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png Binary files differnew file mode 100644 index 000000000000..c85751998077 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png Binary files differindex e08b0e683b76..b168481e669a 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png Binary files differnew file mode 100644 index 000000000000..4af36b7a4e0a --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png Binary files differindex 0c55e8c614dd..9167c7d04dc4 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png Binary files differindex 880564ec506c..7abe43687658 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png Binary files differindex cb6016588f77..737cca7f13a9 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png Binary files differdeleted file mode 100644 index 9a942d28e66a..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png Binary files differnew file mode 100644 index 000000000000..ff8d3aa19b24 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png Binary files differnew file mode 100644 index 000000000000..d422eb7dfe7b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png Binary files differnew file mode 100644 index 000000000000..38602413e723 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_folder.png b/packages/DocumentsUI/res/drawable-hdpi/ic_folder.png Binary files differnew file mode 100644 index 000000000000..3c88982e8245 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_folder.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png Binary files differdeleted file mode 100644 index 7c3d69d47265..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png Binary files differdeleted file mode 100644 index 8b900945cc1f..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png Binary files differdeleted file mode 100644 index 1e41d7aa609f..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png Binary files differindex a6e56ea86bac..e9cfdb1a2c86 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png Binary files differdeleted file mode 100644 index b896c5566262..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_hamburger.png b/packages/DocumentsUI/res/drawable-hdpi/ic_hamburger.png Binary files differnew file mode 100644 index 000000000000..452766744116 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_hamburger.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png Binary files differindex c907bf61c047..f4f9df267624 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png Binary files differindex 1fe7af74f980..396ce5978686 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png Binary files differindex 8a88407fe1a6..ddf9f9a01c7f 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png Binary files differindex 638c8124e3d2..ab4d176549f2 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png Binary files differindex 2a007d2ee9ba..6b01137671ba 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png Binary files differindex 27563277ea63..4eeafadb2863 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png Binary files differindex b00328b50e1c..dca23e6acac5 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png Binary files differindex 03e0cc7aa321..d52840fc5880 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png Binary files differindex cf7d2f4327e9..8ff9ea52b0ba 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png Binary files differindex 0d4cdc197f6d..3563e9704bae 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png Binary files differindex 20dce0fa6793..2d61dc737046 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png Binary files differindex 3f3b536d2ab3..3035ac4aa77e 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png Binary files differindex 79bffc9a1882..d1f26a6dd736 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png Binary files differindex 595c4b9039d4..b0a5f73d7665 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png Binary files differindex 37005129bd85..9497fb0bd156 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png Binary files differdeleted file mode 100644 index 52f1c7044ef7..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_dark.png Binary files differnew file mode 100644 index 000000000000..96d23beb31ff --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_dark.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_light.png Binary files differnew file mode 100644 index 000000000000..032fb17cf401 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_light.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png Binary files differdeleted file mode 100644 index 915e11826ea7..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_dark_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_dark_am.png Binary files differnew file mode 100644 index 000000000000..e2001f75c74e --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_light_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_light_am.png Binary files differnew file mode 100644 index 000000000000..f2cec4fea67c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_light_am.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png Binary files differdeleted file mode 100644 index 303b7f99ffae..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_dark.png Binary files differnew file mode 100644 index 000000000000..6954b421159b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_dark.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_light.png Binary files differnew file mode 100644 index 000000000000..3ede99145325 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_light.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png Binary files differdeleted file mode 100644 index 2375e17575ee..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_dark.png Binary files differnew file mode 100644 index 000000000000..b43fdddbad6b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_dark.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_light.png Binary files differnew file mode 100644 index 000000000000..f0a84020dfe1 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_light.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png Binary files differindex 5c0c87b24013..665ee0bb7ace 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png Binary files differindex 99060cd6fe2c..6be1f5bf571b 100644 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png +++ b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png Binary files differindex 09e77afb6b58..821667e4baca 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png Binary files differindex f42be1389840..4e954c440a41 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png Binary files differindex b47e30623091..6ec12341f0e2 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png Binary files differindex 903a04132d49..73e10816586f 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png Binary files differdeleted file mode 100644 index 4835d5fa37f7..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_dark.png Binary files differnew file mode 100644 index 000000000000..dbe4cb741705 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_dark.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_light.png Binary files differnew file mode 100644 index 000000000000..e9ae09747a89 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_light.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png Binary files differdeleted file mode 100644 index 2d2944273c7c..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_dark.png Binary files differnew file mode 100644 index 000000000000..f8f9eaf7e0a2 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_dark.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_light.png Binary files differnew file mode 100644 index 000000000000..f8635fe147f8 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_light.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png Binary files differindex 318dd5bd3a09..0d3d5d753f50 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png Binary files differindex 932995ee7037..f9597f04fa5b 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png Binary files differdeleted file mode 100644 index cb94d991fe79..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png Binary files differnew file mode 100644 index 000000000000..deba4082414d --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png Binary files differnew file mode 100644 index 000000000000..88f01272a5cb --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png Binary files differindex 240d7f43fc44..b1323da30cda 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png Binary files differindex 6c6aad61e4bc..ff99fd737745 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png Binary files differindex 8fc7bea1d2e9..4af71f3dc37e 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png Binary files differindex 290ad3a915e6..e137ca0cf513 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png Binary files differindex e5eda72cd528..db55b7407ac6 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png Binary files differnew file mode 100644 index 000000000000..3adff716ebc3 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png Binary files differindex 00bd478ad3e8..0a4a8419d35c 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png Binary files differindex a1bd14eafbb0..1dce216259f0 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png Binary files differdeleted file mode 100644 index b81b1e5a126f..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png Binary files differnew file mode 100644 index 000000000000..f061b0c9a701 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png Binary files differnew file mode 100644 index 000000000000..fa3d2ea658cd --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png Binary files differindex 3381c42ffbf3..b558d08a557a 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png Binary files differnew file mode 100644 index 000000000000..efc0b131ce69 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png Binary files differindex 68cc9711b0f6..655d8661853a 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png Binary files differindex 2934e5ace3da..a2f9116fcf69 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png Binary files differindex 95565b3445d7..4aa3a0e0c6a8 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png Binary files differdeleted file mode 100644 index 3a5b798e11cb..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png Binary files differnew file mode 100644 index 000000000000..1b6f00f0f0ad --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png Binary files differnew file mode 100644 index 000000000000..24dad11f29a9 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png Binary files differnew file mode 100644 index 000000000000..7f262529d3a4 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_folder.png b/packages/DocumentsUI/res/drawable-mdpi/ic_folder.png Binary files differnew file mode 100644 index 000000000000..17cb05638860 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_folder.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png Binary files differdeleted file mode 100644 index 567a06bc7606..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png Binary files differdeleted file mode 100644 index 1525572f5b88..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png Binary files differdeleted file mode 100644 index 16c929640006..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png Binary files differindex 6e63b8c6ad44..5534c74ed988 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png Binary files differdeleted file mode 100644 index 11208640b3ab..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_hamburger.png b/packages/DocumentsUI/res/drawable-mdpi/ic_hamburger.png Binary files differnew file mode 100644 index 000000000000..440c0f694033 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_hamburger.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png Binary files differindex fbf5c888bb50..fbd5c21db3ca 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png Binary files differindex ecb4bf20915f..1939ed7714dd 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png Binary files differindex 96b01b975572..bb06624596ac 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png Binary files differindex ee9580947b58..86b925699068 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png Binary files differindex 7a6382824c77..c7f60c405e89 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png Binary files differindex 9ab2f78b7bba..dc9bbc9cc70d 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png Binary files differindex 2d0ab8a6c61e..1f45b99373d6 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png Binary files differindex cf5575a4e834..db6321d8a471 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png Binary files differindex 368fbd610baf..f370056c7396 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png Binary files differindex 2768b1c8de74..86e1cf93bb94 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png Binary files differindex d56db426f056..ed0ee5df871f 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png Binary files differindex 0a0c8f1230b1..6af4222299a0 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png Binary files differindex 8a724ac18735..20197f4c96f9 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png Binary files differindex adfacc1e50f7..dab578baaadc 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png Binary files differindex b17de2d6a059..12e873d3dddc 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png Binary files differdeleted file mode 100644 index 4f903df95a05..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_dark.png Binary files differnew file mode 100644 index 000000000000..d3f3e08ff10c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_dark.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_light.png Binary files differnew file mode 100644 index 000000000000..23663d70c6bf --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_light.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png Binary files differdeleted file mode 100644 index 4352d08d9b1b..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_dark_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_dark_am.png Binary files differnew file mode 100644 index 000000000000..8d9de3d74a08 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_light_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_light_am.png Binary files differnew file mode 100644 index 000000000000..35505fe552ec --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_light_am.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png Binary files differdeleted file mode 100644 index bf9b1b6e1131..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_dark.png Binary files differnew file mode 100644 index 000000000000..67789a32289b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_dark.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_light.png Binary files differnew file mode 100644 index 000000000000..6f8d9a5e31fd --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_light.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png Binary files differdeleted file mode 100644 index 6adc2a373a6c..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_dark.png Binary files differnew file mode 100644 index 000000000000..3b945e1b0670 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_dark.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_light.png Binary files differnew file mode 100644 index 000000000000..7032d5fdc87b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_light.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png Binary files differindex d318dba9b197..a4f474b8d3f3 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png Binary files differindex a7a2b129c1d2..c8c9f1a11e13 100644 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png +++ b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png Binary files differindex 33c8f278ea7a..74fdc2be8420 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png Binary files differindex ef9641d65128..6f8f34f9bd03 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png Binary files differindex 9c3d008d9f1c..d360431c09c6 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png Binary files differindex 4cf4f3f30737..21319d84d4e8 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png Binary files differdeleted file mode 100644 index 17f9f9ef4c79..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_dark.png Binary files differnew file mode 100644 index 000000000000..eeef6960d089 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_dark.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_light.png Binary files differnew file mode 100644 index 000000000000..0b52ce4a5adb --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_light.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png Binary files differdeleted file mode 100644 index 2f9cc588af22..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_dark.png Binary files differnew file mode 100644 index 000000000000..7006326d3fc2 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_dark.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_light.png Binary files differnew file mode 100644 index 000000000000..28b69c60a47d --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_light.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png Binary files differindex e67aa8d132db..8952222cda37 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png Binary files differindex d0e2594f29a9..bc833b4f70b3 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png Binary files differdeleted file mode 100644 index 2e66f0372741..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png Binary files differnew file mode 100644 index 000000000000..c782d0f689f6 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png Binary files differnew file mode 100644 index 000000000000..fbc1e24e5b7f --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png Binary files differindex 64e0d4254ca7..de17d0be0584 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png Binary files differindex a4f70ba2c53f..d3967458d51a 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png Binary files differindex 4897221c597d..1627d8ecd73f 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png Binary files differindex 4cec994e6bbe..a6f91b5d6b1b 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png Binary files differindex 5e46b71eeb80..cff0ab6632c7 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png Binary files differnew file mode 100644 index 000000000000..884dd58dce3d --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png Binary files differindex 977cfd2a84f5..9f70fb8d1929 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png Binary files differindex e05c4b48d52d..7fb5ef659f45 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png Binary files differdeleted file mode 100644 index 98d3f7954123..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png Binary files differnew file mode 100644 index 000000000000..49e4d0a6903e --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png Binary files differnew file mode 100644 index 000000000000..09609e30becf --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png Binary files differindex ff2ff14311de..cdb84718d23e 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png Binary files differnew file mode 100644 index 000000000000..f3199294df17 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png Binary files differindex 291737751acc..ee8f63c5e300 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png Binary files differindex 87c6538c1bc5..faa648d497dc 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png Binary files differindex 97c45002cbbc..872a67be3853 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png Binary files differdeleted file mode 100644 index 1a8e632c2888..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png Binary files differnew file mode 100644 index 000000000000..aaa951b0c20c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png Binary files differnew file mode 100644 index 000000000000..134208753540 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png Binary files differnew file mode 100644 index 000000000000..8c883ad15a7b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_folder.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_folder.png Binary files differnew file mode 100644 index 000000000000..0d3f8697e4b5 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_folder.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png Binary files differdeleted file mode 100644 index 8f7f4ab94236..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png Binary files differdeleted file mode 100644 index b82ae20239a5..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png Binary files differdeleted file mode 100644 index edd626675c2f..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png Binary files differindex c3af9ec372ac..a1c9789a762c 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png Binary files differdeleted file mode 100644 index 60ce8d548fbe..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_hamburger.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_hamburger.png Binary files differnew file mode 100644 index 000000000000..f7a17790e649 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_hamburger.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png Binary files differindex c650185a7203..295576cf37a1 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png Binary files differindex 0771ed2c1f20..19c19baa34a8 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png Binary files differindex 91c31e3baecb..22cbd7b778de 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png Binary files differindex f06b298fdf82..bbdee7e7dd77 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png Binary files differindex c3a7eaab075e..7a050c926a62 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png Binary files differindex 17e09b363a5f..8ccca6322827 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png Binary files differindex 0ab604f5479c..4c87e593439f 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png Binary files differindex 5054fc8fefdf..d0929cf2399a 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png Binary files differindex d3d386e28835..e55b3475b6be 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png Binary files differindex f24ca1a855fa..28b7d5ce8165 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png Binary files differindex 82c1a30f1f1c..1121c43e104b 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png Binary files differindex 02583123cff7..47b533359613 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png Binary files differindex ccace9d278f1..62ab8fba2615 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png Binary files differindex a56940a1d5b7..f9694188363f 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png Binary files differindex f6a0af405a89..204b04de19e4 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png Binary files differdeleted file mode 100644 index 6c6447e59f44..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_dark.png Binary files differnew file mode 100644 index 000000000000..2460761b9e5b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_dark.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_light.png Binary files differnew file mode 100644 index 000000000000..1de024741e98 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_light.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png Binary files differdeleted file mode 100644 index c916e0be7687..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_dark_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_dark_am.png Binary files differnew file mode 100644 index 000000000000..f9788b110352 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_light_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_light_am.png Binary files differnew file mode 100644 index 000000000000..ff307cd55417 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_light_am.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png Binary files differdeleted file mode 100644 index 714f2ee23155..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_dark.png Binary files differnew file mode 100644 index 000000000000..be89734d7d7c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_dark.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_light.png Binary files differnew file mode 100644 index 000000000000..90d1e15b556e --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_light.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png Binary files differdeleted file mode 100644 index 6016c080c499..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_dark.png Binary files differnew file mode 100644 index 000000000000..f788f23b0cde --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_dark.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_light.png Binary files differnew file mode 100644 index 000000000000..bc2acbeec46f --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_light.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png Binary files differindex b05b9a4d0450..6ccfb768d91b 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png Binary files differindex 1da819658882..94a757a057b2 100644 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png +++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png Binary files differindex 06681e3c1c35..21272f4144c6 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png Binary files differindex ac88818c154b..6824bce14e54 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png Binary files differindex 88356c7c03b6..81d7816685ce 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png Binary files differindex 75658db58dc0..99c3dbbeca1e 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png Binary files differdeleted file mode 100644 index 8bee0dc21f36..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_dark.png Binary files differnew file mode 100644 index 000000000000..a91cd764b689 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_dark.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_light.png Binary files differnew file mode 100644 index 000000000000..73e440a92c00 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_light.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png Binary files differdeleted file mode 100644 index ad6c59b33b7c..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_dark.png Binary files differnew file mode 100644 index 000000000000..aff4bc4273b2 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_dark.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_light.png Binary files differnew file mode 100644 index 000000000000..7e0fa622f18c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_light.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png Binary files differindex 4c56bd0c9445..e7151cff39e4 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png Binary files differindex 5f642293fbd5..5c105934ddce 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png Binary files differdeleted file mode 100644 index 48ab9c77f50a..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png Binary files differnew file mode 100644 index 000000000000..e96ed9908c52 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png Binary files differnew file mode 100644 index 000000000000..cac2aafafb31 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png Binary files differindex 68e619e6c45d..1ee08755fd51 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png Binary files differindex 945119aa105d..8d3dabfad80d 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png Binary files differindex bf49d787fcc2..c3e21ae9698a 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png Binary files differindex 5263365008a6..e809fe6536ce 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png Binary files differindex 77a0faec5c50..5ed0373f549d 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png Binary files differnew file mode 100644 index 000000000000..1a373f36a4fd --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png Binary files differindex 30d2c4c383c5..b4308b49b7a9 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png Binary files differindex c098866320d2..b5ba48b33c61 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png Binary files differdeleted file mode 100644 index 06d8d9c5614d..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png Binary files differnew file mode 100644 index 000000000000..63e425551c61 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png Binary files differnew file mode 100644 index 000000000000..6237ded1c00b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png Binary files differindex a3b146bdd76b..2c0a81ecc973 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png Binary files differnew file mode 100644 index 000000000000..2fba5edb2e16 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png Binary files differindex c09d6ab855c3..3e391ced05ae 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png Binary files differindex 2170e666d1fa..372abc9a9c72 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png Binary files differindex bc4ce7921cba..e535ca387cb6 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png Binary files differdeleted file mode 100644 index 42d8ec174bef..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png Binary files differnew file mode 100644 index 000000000000..48b4a728bce4 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png Binary files differnew file mode 100644 index 000000000000..15d6c503ded6 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png Binary files differnew file mode 100644 index 000000000000..9ccf41ec21b2 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_folder.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_folder.png Binary files differnew file mode 100644 index 000000000000..9bedcd9f0d16 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_folder.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png Binary files differdeleted file mode 100644 index 7bbaf9dc4f7c..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png Binary files differdeleted file mode 100644 index 901af807f7a7..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png Binary files differdeleted file mode 100644 index e21e350e2e93..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png Binary files differindex 86a74cdabc51..10cdd5163820 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png Binary files differdeleted file mode 100644 index 988c85630ded..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_hamburger.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_hamburger.png Binary files differnew file mode 100644 index 000000000000..355f61f1657b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_hamburger.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png Binary files differindex f23e23c5c863..7f483e168631 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png Binary files differindex f67c72e840d9..c19988f9e8cc 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png Binary files differindex 676d0f76972b..d10bec8ea9e6 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png Binary files differindex b17ba1d0c2c9..4013b7caae4a 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png Binary files differindex 58f13817ef82..036127c94cf3 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png Binary files differindex eed0eafb9b07..0fef9d09e87a 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png Binary files differindex 40fb3924fb67..af7950770dbc 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png Binary files differindex b988ab503877..db2ef7b25631 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png Binary files differindex 6ace932eead9..e6befadcbb9e 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png Binary files differindex 8f19afa98825..89bf79f7d7d4 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png Binary files differindex e4c9f8aa0b79..7acc684e5e85 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png Binary files differindex 9e27d63757cf..0bee75ae8f6e 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png Binary files differindex e4c679aa8626..da13073d9d41 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png Binary files differindex b467962459bf..7196ee5b4898 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png Binary files differindex 5f5a86f793f1..6fa2216bcf0a 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png Binary files differdeleted file mode 100644 index 3b8afc9f191b..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_dark.png Binary files differnew file mode 100644 index 000000000000..067aa655038c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_dark.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_light.png Binary files differnew file mode 100644 index 000000000000..40437a83414c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_light.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png Binary files differdeleted file mode 100644 index 077c851cee28..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_dark_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_dark_am.png Binary files differnew file mode 100644 index 000000000000..069d95104e56 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_dark_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_light_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_light_am.png Binary files differnew file mode 100644 index 000000000000..17250251c177 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_light_am.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png Binary files differdeleted file mode 100644 index a3215f2d4f39..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_dark.png Binary files differnew file mode 100644 index 000000000000..d149239ee439 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_dark.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_light.png Binary files differnew file mode 100644 index 000000000000..9a06663e2b4a --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_light.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png Binary files differdeleted file mode 100644 index 873a5534ca41..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_dark.png Binary files differnew file mode 100644 index 000000000000..429f3c55de18 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_dark.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_light.png Binary files differnew file mode 100644 index 000000000000..bcfe7fd08912 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_light.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png Binary files differindex d213e7c28bce..c31b4dc04c17 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png Binary files differindex db53a011f09d..d852b8ec4325 100644 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png +++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid.xml b/packages/DocumentsUI/res/drawable/grid_protect_background.xml index 3f036f7a21bd..2e7aadd9579a 100644 --- a/packages/DocumentsUI/res/drawable/item_doc_grid.xml +++ b/packages/DocumentsUI/res/drawable/grid_protect_background.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project +<!-- 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. @@ -15,5 +15,10 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:drawable="@drawable/ic_grid_card_background" /> + <item android:state_enabled="false"> + <color android:color="#88000000" /> + </item> + <item> + <color android:color="#88252525" /> + </item> </selector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_video.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio_dark.xml index e1962622ca7e..768d4092dcce 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_video.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_audio_dark.xml @@ -18,6 +18,6 @@ --> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_video_am" + android:src="@drawable/ic_doc_audio_dark_am" android:autoMirrored="true"> </bitmap>
\ No newline at end of file diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio_light.xml index c6ccea63c1b0..bdb6983854e6 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_audio_light.xml @@ -18,6 +18,6 @@ --> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_audio_am" + android:src="@drawable/ic_doc_audio_light_am" android:autoMirrored="true"> </bitmap>
\ No newline at end of file diff --git a/packages/DocumentsUI/res/drawable/ic_root_folder.xml b/packages/DocumentsUI/res/drawable/ic_doc_video_dark.xml index a3c8f617231f..4fb82bbd24a5 100644 --- a/packages/DocumentsUI/res/drawable/ic_root_folder.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_video_dark.xml @@ -18,6 +18,6 @@ --> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_root_folder_am" + android:src="@drawable/ic_doc_video_dark_am" android:autoMirrored="true"> </bitmap>
\ No newline at end of file diff --git a/packages/DocumentsUI/res/drawable/ic_doc_video_light.xml b/packages/DocumentsUI/res/drawable/ic_doc_video_light.xml new file mode 100644 index 000000000000..290c3f1a9dfd --- /dev/null +++ b/packages/DocumentsUI/res/drawable/ic_doc_video_light.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_doc_video_light_am" + android:autoMirrored="true"> +</bitmap>
\ No newline at end of file diff --git a/packages/DocumentsUI/res/drawable/ic_root_folder_dark.xml b/packages/DocumentsUI/res/drawable/ic_root_folder_dark.xml new file mode 100644 index 000000000000..8e29d1d8c5c7 --- /dev/null +++ b/packages/DocumentsUI/res/drawable/ic_root_folder_dark.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_root_folder_dark_am" + android:autoMirrored="true"> +</bitmap>
\ No newline at end of file diff --git a/packages/DocumentsUI/res/drawable/ic_root_folder_light.xml b/packages/DocumentsUI/res/drawable/ic_root_folder_light.xml new file mode 100644 index 000000000000..a750f1f79075 --- /dev/null +++ b/packages/DocumentsUI/res/drawable/ic_root_folder_light.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_root_folder_light_am" + android:autoMirrored="true"> +</bitmap>
\ No newline at end of file diff --git a/packages/DocumentsUI/res/drawable/item_activated.xml b/packages/DocumentsUI/res/drawable/item_activated.xml new file mode 100644 index 000000000000..6ffefdbd03ef --- /dev/null +++ b/packages/DocumentsUI/res/drawable/item_activated.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" android:state_activated="true" android:drawable="@color/accent_item_activated" /> + <item android:state_focused="false" android:state_activated="true" android:drawable="@color/accent_item_activated" /> + <item android:drawable="@android:color/transparent" /> +</selector> diff --git a/packages/DocumentsUI/res/drawable/item_background.xml b/packages/DocumentsUI/res/drawable/item_background.xml deleted file mode 100644 index ec9be6d18447..000000000000 --- a/packages/DocumentsUI/res/drawable/item_background.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - - <item android:state_window_focused="false" android:drawable="@android:color/transparent" /> - - <item android:state_focused="true" android:state_activated="true" android:drawable="@drawable/ic_grid_card_focused" /> - <item android:state_focused="false" android:state_activated="true" android:drawable="@drawable/ic_grid_card_focused" /> - - <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/ic_grid_card_pressed" /> - <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/ic_grid_card_pressed" /> - <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/ic_grid_card_pressed" /> - <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/ic_grid_card_pressed" /> - <item android:state_focused="true" android:drawable="@drawable/ic_grid_card_pressed" /> - - <item android:drawable="@android:color/transparent" /> - -</selector> diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml index adbb9da4323f..5f1e432dac80 100644 --- a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml +++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml @@ -14,103 +14,111 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/item_background" - android:minHeight="?android:attr/listPreferredItemHeight" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingTop="8dp" - android:paddingBottom="8dp" - android:gravity="center_vertical" - android:orientation="horizontal" - android:baselineAligned="false"> - - <FrameLayout - android:id="@android:id/icon" - android:layout_width="@dimen/icon_size" - android:layout_height="@dimen/icon_size" - android:layout_marginStart="12dp" - android:layout_marginEnd="20dp"> - - <ImageView - android:id="@+id/icon_mime" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerInside" - android:contentDescription="@null" /> - - <ImageView - android:id="@+id/icon_thumb" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerCrop" - android:contentDescription="@null" /> - - </FrameLayout> - - <!-- This is the one special case where we want baseline alignment! --> + android:foreground="@drawable/item_activated"> + <LinearLayout - android:layout_width="0dp" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="1" - android:orientation="horizontal"> - - <TextView - android:id="@android:id/title" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="0.5" - android:layout_marginEnd="12dp" - android:singleLine="true" - android:ellipsize="middle" - android:textAlignment="viewStart" - style="@style/TextAppearance.Medium" /> - - <ImageView - android:id="@android:id/icon1" - android:layout_width="@dimen/root_icon_size" - android:layout_height="@dimen/root_icon_size" - android:layout_marginEnd="8dp" - android:scaleType="centerInside" - android:contentDescription="@null" /> - - <TextView - android:id="@android:id/summary" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="0.25" - android:layout_marginEnd="12dp" - android:singleLine="true" - android:ellipsize="end" - android:textAlignment="viewStart" - style="@style/TextAppearance.Small" /> - - <TextView - android:id="@+id/size" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="0.125" - android:layout_marginEnd="12dp" - android:minWidth="70dp" - android:singleLine="true" - android:ellipsize="end" - android:textAlignment="viewEnd" - style="@style/TextAppearance.Small" /> - - <TextView - android:id="@+id/date" + android:minHeight="@dimen/list_item_height" + android:paddingStart="@dimen/list_item_padding" + android:paddingEnd="@dimen/list_item_padding" + android:gravity="center_vertical" + android:orientation="horizontal" + android:baselineAligned="false"> + + <FrameLayout + android:id="@android:id/icon" + android:layout_width="@dimen/icon_size" + android:layout_height="@dimen/icon_size" + android:layout_marginStart="0dp" + android:layout_marginEnd="16dp"> + + <ImageView + android:id="@+id/icon_mime" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + <ImageView + android:id="@+id/icon_thumb" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="centerCrop" + android:contentDescription="@null" /> + + </FrameLayout> + + <!-- This is the one special case where we want baseline alignment! --> + <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_weight="0.125" - android:layout_marginEnd="12dp" - android:minWidth="70dp" - android:singleLine="true" - android:ellipsize="end" - android:textAlignment="viewEnd" - style="@style/TextAppearance.Small" /> + android:layout_weight="1" + android:orientation="horizontal"> + + <TextView + android:id="@android:id/title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.5" + android:layout_marginEnd="12dp" + android:singleLine="true" + android:ellipsize="middle" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:textColor="?android:attr/textColorPrimary" /> + + <ImageView + android:id="@android:id/icon1" + android:layout_width="@dimen/root_icon_size" + android:layout_height="@dimen/root_icon_size" + android:layout_marginEnd="8dp" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + <TextView + android:id="@android:id/summary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.25" + android:layout_marginEnd="12dp" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorSecondary" /> + + <TextView + android:id="@+id/size" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.125" + android:layout_marginEnd="12dp" + android:minWidth="70dp" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewEnd" + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorSecondary" /> + + <TextView + android:id="@+id/date" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.125" + android:layout_marginEnd="12dp" + android:minWidth="70dp" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewEnd" + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorSecondary" /> + + </LinearLayout> </LinearLayout> -</LinearLayout> +</FrameLayout> diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml index 77cdc3ba067e..09b50c0e1b55 100644 --- a/packages/DocumentsUI/res/layout/fragment_directory.xml +++ b/packages/DocumentsUI/res/layout/fragment_directory.xml @@ -31,8 +31,7 @@ <ListView android:id="@+id/list" android:layout_width="match_parent" - android:layout_height="match_parent" - android:listSelector="@android:color/transparent" /> + android:layout_height="match_parent" /> <GridView android:id="@+id/grid" @@ -40,11 +39,13 @@ android:layout_height="match_parent" android:paddingStart="@dimen/grid_padding_horiz" android:paddingEnd="@dimen/grid_padding_horiz" - android:paddingTop="@dimen/grid_padding" - android:paddingBottom="@dimen/grid_padding" + android:paddingTop="@dimen/grid_padding_vert" + android:paddingBottom="@dimen/grid_padding_vert" + android:horizontalSpacing="@dimen/grid_item_padding" + android:verticalSpacing="@dimen/grid_item_padding" android:clipToPadding="false" android:scrollbarStyle="outsideOverlay" - android:listSelector="@android:color/transparent" + android:drawSelectorOnTop="true" android:visibility="gone" /> </com.android.documentsui.DirectoryView> diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml index 3aef1cd3bca5..0fc606dd7d79 100644 --- a/packages/DocumentsUI/res/layout/item_doc_grid.xml +++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml @@ -16,110 +16,111 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="@dimen/grid_height" - android:background="@drawable/item_doc_grid" - android:foreground="@drawable/item_background"> + android:layout_height="@dimen/grid_item_height" + android:orientation="vertical" + android:background="@color/grid_item_background" + android:foreground="@drawable/item_activated"> + + <ImageView + android:id="@+id/icon_thumb" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="centerCrop" + android:contentDescription="@null" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingBottom="6dp" android:orientation="vertical"> - <FrameLayout + <ImageView + android:id="@+id/icon_mime" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" - android:layout_marginBottom="6dp" - android:background="#fff" - android:foreground="@drawable/ic_grid_gradient_bg" - android:foregroundGravity="fill"> - - <ImageView - android:id="@+id/icon_mime" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerInside" - android:contentDescription="@null" /> - - <ImageView - android:id="@+id/icon_thumb" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerCrop" - android:contentDescription="@null" /> - - </FrameLayout> + android:scaleType="centerInside" + android:contentDescription="@null" /> <LinearLayout - android:id="@+id/line1" android:layout_width="match_parent" android:layout_height="wrap_content" - android:gravity="center_vertical" - android:orientation="horizontal" - android:baselineAligned="false" + android:background="@drawable/grid_protect_background" + android:orientation="vertical" android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> - - <TextView - android:id="@android:id/title" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:singleLine="true" - android:ellipsize="middle" - android:textAlignment="viewStart" - style="@style/TextAppearance.Medium" /> - - <ImageView - android:id="@android:id/icon1" - android:layout_width="@dimen/root_icon_size" - android:layout_height="@dimen/root_icon_size" - android:layout_marginStart="8dp" - android:scaleType="centerInside" - android:contentDescription="@null" /> + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:paddingTop="8dp" + android:paddingBottom="8dp"> - </LinearLayout> - - <LinearLayout - android:id="@+id/line2" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center_vertical" - android:orientation="horizontal" - android:baselineAligned="false" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> - - <TextView - android:id="@+id/date" - android:layout_width="0dp" + <LinearLayout + android:id="@+id/line1" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="0.5" - android:singleLine="true" - android:ellipsize="end" - android:textAlignment="viewStart" - style="@style/TextAppearance.Small" /> - - <TextView - android:id="@+id/size" - android:layout_width="0dp" + android:gravity="center_vertical" + android:orientation="horizontal" + android:baselineAligned="false"> + + <TextView + android:id="@android:id/title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:singleLine="true" + android:ellipsize="middle" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:textColor="?android:attr/textColorPrimaryInverse" /> + + <ImageView + android:id="@android:id/icon1" + android:layout_width="@dimen/root_icon_size" + android:layout_height="@dimen/root_icon_size" + android:layout_marginStart="8dp" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/line2" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="0.5" - android:layout_marginStart="8dp" - android:singleLine="true" - android:ellipsize="end" - android:textAlignment="viewStart" - style="@style/TextAppearance.Small" /> - - <ImageView - android:id="@android:id/icon2" - android:layout_width="@dimen/root_icon_size" - android:layout_height="@dimen/root_icon_size" - android:layout_marginStart="8dp" - android:scaleType="centerInside" - android:contentDescription="@null" - android:visibility="gone" /> + android:gravity="center_vertical" + android:orientation="horizontal" + android:baselineAligned="false"> + + <TextView + android:id="@+id/date" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.5" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Caption" + android:textColor="?android:attr/textColorPrimaryInverse" /> + + <TextView + android:id="@+id/size" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.5" + android:layout_marginStart="8dp" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Caption" + android:textColor="?android:attr/textColorPrimaryInverse" /> + + <ImageView + android:id="@android:id/icon2" + android:layout_width="@dimen/root_icon_size" + android:layout_height="@dimen/root_icon_size" + android:layout_marginStart="8dp" + android:scaleType="centerInside" + android:contentDescription="@null" + android:visibility="gone" /> + + </LinearLayout> </LinearLayout> diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml index e3a0dddea66c..50ed2d6167e7 100644 --- a/packages/DocumentsUI/res/layout/item_doc_list.xml +++ b/packages/DocumentsUI/res/layout/item_doc_list.xml @@ -14,114 +14,121 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/item_background" - android:minHeight="?android:attr/listPreferredItemHeight" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingTop="8dp" - android:paddingBottom="8dp" - android:gravity="center_vertical" - android:orientation="horizontal" - android:baselineAligned="false"> - - <FrameLayout - android:id="@android:id/icon" - android:layout_width="@dimen/icon_size" - android:layout_height="@dimen/icon_size" - android:layout_marginStart="12dp" - android:layout_marginEnd="20dp"> - - <ImageView - android:id="@+id/icon_mime" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerInside" - android:contentDescription="@null" /> - - <ImageView - android:id="@+id/icon_thumb" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerCrop" - android:contentDescription="@null" /> - - </FrameLayout> + android:foreground="@drawable/item_activated"> <LinearLayout - android:layout_width="0dp" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="1" - android:orientation="vertical"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:baselineAligned="false"> - - <TextView - android:id="@android:id/title" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:singleLine="true" - android:ellipsize="middle" - android:textAlignment="viewStart" - style="@style/TextAppearance.Medium" /> + android:minHeight="@dimen/list_item_height" + android:paddingStart="@dimen/list_item_padding" + android:paddingEnd="@dimen/list_item_padding" + android:gravity="center_vertical" + android:orientation="horizontal" + android:baselineAligned="false"> + + <FrameLayout + android:id="@android:id/icon" + android:layout_width="@dimen/icon_size" + android:layout_height="@dimen/icon_size" + android:layout_marginEnd="16dp"> <ImageView - android:id="@android:id/icon1" - android:layout_width="@dimen/root_icon_size" - android:layout_height="@dimen/root_icon_size" - android:layout_marginStart="8dp" + android:id="@+id/icon_mime" + android:layout_width="wrap_content" + android:layout_height="match_parent" android:scaleType="centerInside" android:contentDescription="@null" /> - </LinearLayout> + <ImageView + android:id="@+id/icon_thumb" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="centerCrop" + android:contentDescription="@null" /> + + </FrameLayout> <LinearLayout - android:id="@+id/line2" - android:layout_width="match_parent" + android:layout_width="0dp" android:layout_height="wrap_content" - android:gravity="center_vertical" - android:orientation="horizontal" - android:baselineAligned="false"> + android:layout_weight="1" + android:orientation="vertical"> - <TextView - android:id="@+id/date" - android:layout_width="90dp" - android:layout_height="wrap_content" - android:singleLine="true" - android:ellipsize="end" - android:textAlignment="viewStart" - style="@style/TextAppearance.Small" /> - - <TextView - android:id="@+id/size" - android:layout_width="90dp" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:singleLine="true" - android:ellipsize="end" - android:textAlignment="viewStart" - style="@style/TextAppearance.Small" /> - - <TextView - android:id="@android:id/summary" - android:layout_width="0dp" + android:orientation="horizontal" + android:baselineAligned="false"> + + <TextView + android:id="@android:id/title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:singleLine="true" + android:ellipsize="middle" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:textColor="?android:attr/textColorPrimary" /> + + <ImageView + android:id="@android:id/icon1" + android:layout_width="@dimen/root_icon_size" + android:layout_height="@dimen/root_icon_size" + android:layout_marginStart="8dp" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/line2" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_marginStart="8dp" - android:singleLine="true" - android:ellipsize="end" - android:textAlignment="viewStart" - style="@style/TextAppearance.Small" /> + android:gravity="center_vertical" + android:orientation="horizontal" + android:baselineAligned="false"> + + <TextView + android:id="@+id/date" + android:layout_width="90dp" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorSecondary" /> + + <TextView + android:id="@+id/size" + android:layout_width="90dp" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorSecondary" /> + + <TextView + android:id="@android:id/summary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginStart="8dp" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorSecondary" /> + + </LinearLayout> </LinearLayout> </LinearLayout> -</LinearLayout> +</FrameLayout> diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml index 0bf6137b7464..005a111beabd 100644 --- a/packages/DocumentsUI/res/layout/item_loading_grid.xml +++ b/packages/DocumentsUI/res/layout/item_loading_grid.xml @@ -17,11 +17,6 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="@dimen/grid_height" - android:minHeight="?android:attr/listPreferredItemHeight" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingTop="8dp" - android:paddingBottom="8dp" android:orientation="horizontal"> <ProgressBar diff --git a/packages/DocumentsUI/res/layout/item_loading_list.xml b/packages/DocumentsUI/res/layout/item_loading_list.xml index cdcd01d2ad94..6f214edea8c4 100644 --- a/packages/DocumentsUI/res/layout/item_loading_list.xml +++ b/packages/DocumentsUI/res/layout/item_loading_list.xml @@ -17,11 +17,7 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeight" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingTop="8dp" - android:paddingBottom="8dp"> + android:minHeight="@dimen/list_item_height"> <ProgressBar android:layout_width="wrap_content" diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml index b3bdd28c9598..385563df64f6 100644 --- a/packages/DocumentsUI/res/layout/item_message_grid.xml +++ b/packages/DocumentsUI/res/layout/item_message_grid.xml @@ -17,11 +17,10 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="@dimen/grid_height" - android:paddingTop="?android:attr/listPreferredItemPaddingStart" android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingBottom="?android:attr/listPreferredItemPaddingEnd" - android:foreground="@drawable/item_background"> + android:paddingTop="8dp" + android:paddingBottom="8dp"> <LinearLayout android:layout_width="match_parent" @@ -42,9 +41,10 @@ android:gravity="center" android:maxLines="4" android:ellipsize="end" - android:paddingTop="6dp" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textAlignment="viewStart" /> + android:paddingTop="8dp" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorPrimary" /> </LinearLayout> diff --git a/packages/DocumentsUI/res/layout/item_message_list.xml b/packages/DocumentsUI/res/layout/item_message_list.xml index 2bcbc2d30c2f..44c8baf8cb68 100644 --- a/packages/DocumentsUI/res/layout/item_message_list.xml +++ b/packages/DocumentsUI/res/layout/item_message_list.xml @@ -17,23 +17,28 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/item_background" - android:minHeight="?android:attr/listPreferredItemHeight" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:minHeight="@dimen/list_item_height" + android:paddingStart="@dimen/list_item_padding" + android:paddingEnd="@dimen/list_item_padding" android:paddingTop="8dp" android:paddingBottom="8dp" + android:gravity="center_vertical" android:orientation="horizontal" android:baselineAligned="false"> - <ImageView - android:id="@android:id/icon" - android:layout_width="@android:dimen/app_icon_size" - android:layout_height="@android:dimen/app_icon_size" - android:layout_marginEnd="8dp" - android:layout_gravity="center_vertical" - android:scaleType="centerInside" - android:contentDescription="@null" /> + <FrameLayout + android:layout_width="@dimen/icon_size" + android:layout_height="@dimen/icon_size" + android:layout_marginEnd="16dp"> + + <ImageView + android:id="@android:id/icon" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + </FrameLayout> <TextView android:id="@android:id/title" @@ -43,6 +48,7 @@ android:maxLines="2" android:ellipsize="end" android:textAlignment="viewStart" - android:textAppearance="?android:attr/textAppearanceSmall" /> + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorPrimary" /> </LinearLayout> diff --git a/packages/DocumentsUI/res/values-ldrtl/dimens.xml b/packages/DocumentsUI/res/values-ldrtl/dimens.xml new file mode 100644 index 000000000000..22f8131474c4 --- /dev/null +++ b/packages/DocumentsUI/res/values-ldrtl/dimens.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <bool name="list_divider_inset_left">false</bool> +</resources> diff --git a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml index 961608cfe120..c9dee8d2c174 100644 --- a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml +++ b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml @@ -16,4 +16,10 @@ <resources> <bool name="always_show_summary">true</bool> + + <dimen name="list_item_height">64dp</dimen> + <dimen name="list_item_padding">24dp</dimen> + + <dimen name="list_divider_inset">80dp</dimen> + </resources> diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml index 3a75dfad6761..75afe0145d03 100644 --- a/packages/DocumentsUI/res/values-sw720dp/dimens.xml +++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml @@ -20,5 +20,9 @@ <item type="dimen" name="dialog_width">85%</item> <item type="dimen" name="dialog_height">90%</item> - <dimen name="grid_padding_horiz">20dp</dimen> + <dimen name="grid_padding_horiz">24dp</dimen> + <dimen name="grid_padding_vert">8dp</dimen> + + <dimen name="grid_item_padding">8dp</dimen> + </resources> diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml index adeff77855dd..e3d7f2d6a7a7 100644 --- a/packages/DocumentsUI/res/values/colors.xml +++ b/packages/DocumentsUI/res/values/colors.xml @@ -18,4 +18,9 @@ <color name="chip">#ddd</color> <color name="item_root_pressed">#33cccccc</color> <color name="item_root_focused">#66cccccc</color> + + <color name="grid_item_background">#ffe1e1e0</color> + + <color name="accent_item_activated">#88009587</color> + </resources> diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml index 924a8d6c6d5a..83a0bf4ae32c 100644 --- a/packages/DocumentsUI/res/values/dimens.xml +++ b/packages/DocumentsUI/res/values/dimens.xml @@ -15,14 +15,26 @@ --> <resources> - <dimen name="icon_size">32dp</dimen> + <dimen name="icon_size">40dp</dimen> <dimen name="root_icon_size">24dp</dimen> + <dimen name="grid_width">160dp</dimen> - <dimen name="grid_height">170dp</dimen> + <dimen name="grid_height">176dp</dimen> + + <dimen name="grid_item_width">160dp</dimen> + <dimen name="grid_item_height">176dp</dimen> + <dimen name="grid_item_padding">4dp</dimen> - <dimen name="grid_padding">4dp</dimen> <dimen name="grid_padding_horiz">4dp</dimen> + <dimen name="grid_padding_vert">4dp</dimen> + + <dimen name="list_item_height">72dp</dimen> + <dimen name="list_item_padding">16dp</dimen> + + <dimen name="list_divider_inset">72dp</dimen> + <bool name="list_divider_inset_left">true</bool> <bool name="show_as_dialog">false</bool> <bool name="always_show_summary">false</bool> + </resources> diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java index 77595b687e0c..00b3c87f6d2a 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java @@ -29,12 +29,18 @@ public class DirectoryContainerView extends FrameLayout { public DirectoryContainerView(Context context) { super(context); - setClipChildren(false); } public DirectoryContainerView(Context context, AttributeSet attrs) { super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); setClipChildren(false); + setClipToOutline(false); + setClipToPadding(false); } @Override diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index 9069a55404ee..e013cc3fac7f 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -38,6 +38,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.Loader; +import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Point; @@ -187,6 +188,7 @@ public class DirectoryFragment extends Fragment { public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final Context context = inflater.getContext(); + final Resources res = context.getResources(); final View view = inflater.inflate(R.layout.fragment_directory, container, false); mEmptyView = view.findViewById(android.R.id.empty); @@ -196,6 +198,16 @@ public class DirectoryFragment extends Fragment { mListView.setMultiChoiceModeListener(mMultiListener); mListView.setRecyclerListener(mRecycleListener); + // Indent our list divider to align with text + final Drawable divider = mListView.getDivider(); + final boolean insetLeft = res.getBoolean(R.bool.list_divider_inset_left); + final int insetSize = res.getDimensionPixelSize(R.dimen.list_divider_inset); + if (insetLeft) { + mListView.setDivider(new InsetDrawable(divider, insetSize, 0, 0, 0)); + } else { + mListView.setDivider(new InsetDrawable(divider, 0, 0, insetSize, 0)); + } + mGridView = (GridView) view.findViewById(R.id.grid); mGridView.setOnItemClickListener(mItemListener); mGridView.setMultiChoiceModeListener(mMultiListener); @@ -693,11 +705,11 @@ public class DirectoryFragment extends Fragment { if (extras != null) { final String info = extras.getString(DocumentsContract.EXTRA_INFO); if (info != null) { - mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info, info)); + mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info_dark, info)); } final String error = extras.getString(DocumentsContract.EXTRA_ERROR); if (error != null) { - mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, error)); + mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert_dark, error)); } if (extras.getBoolean(DocumentsContract.EXTRA_LOADING, false)) { mFooters.add(new LoadingFooter()); @@ -706,7 +718,7 @@ public class DirectoryFragment extends Fragment { if (result != null && result.exception != null) { mFooters.add(new MessageFooter( - 3, R.drawable.ic_dialog_alert, getString(R.string.query_error))); + 3, R.drawable.ic_dialog_alert_dark, getString(R.string.query_error))); } if (isEmpty()) { @@ -748,21 +760,6 @@ public class DirectoryFragment extends Fragment { convertView = inflater.inflate(R.layout.item_doc_list, parent, false); } else if (state.derivedMode == MODE_GRID) { convertView = inflater.inflate(R.layout.item_doc_grid, parent, false); - - // Apply padding to grid items - final FrameLayout grid = (FrameLayout) convertView; - final int gridPadding = getResources() - .getDimensionPixelSize(R.dimen.grid_padding); - - // Tricksy hobbitses! We need to fully clear the drawable so - // the view doesn't clobber the new InsetDrawable callback - // when setting back later. - final Drawable fg = grid.getForeground(); - final Drawable bg = grid.getBackground(); - grid.setForeground(null); - grid.setBackground(null); - grid.setForeground(new InsetDrawable(fg, gridPadding)); - grid.setBackground(new InsetDrawable(bg, gridPadding)); } else { throw new IllegalStateException(); } @@ -882,7 +879,8 @@ public class DirectoryFragment extends Fragment { // hint to remind user they're a directory. if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID && showThumbnail) { - iconDrawable = context.getResources().getDrawable(R.drawable.ic_root_folder); + iconDrawable = context.getResources().getDrawable( + R.drawable.ic_root_folder_dark); } if (summary != null) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java index b552e5aa838c..c163c468da58 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java @@ -40,8 +40,13 @@ public class DirectoryView extends FrameLayout { public void setBackground(Drawable background) { final Rect rect = new Rect(); background.getPadding(rect); - final InsetDrawable inset = new InsetDrawable(background, -rect.left, 0, -rect.right, 0); - super.setBackground(inset); + + final boolean insetLeft = getResources().getBoolean(R.bool.list_divider_inset_left); + if (insetLeft) { + super.setBackground(new InsetDrawable(background, -rect.left, 0, -rect.right, 0)); + } else { + super.setBackground(new InsetDrawable(background, -rect.right, 0, -rect.left, 0)); + } } @Override diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java index 71fd100b803b..eaa74ebfef20 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java +++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java @@ -45,7 +45,7 @@ public class IconUtils { add("application/vnd.android.package-archive", icon); // Audio - icon = R.drawable.ic_doc_audio; + icon = R.drawable.ic_doc_audio_dark; add("application/ogg", icon); add("application/x-flac", icon); @@ -132,7 +132,7 @@ public class IconUtils { add("application/x-font-ttf", icon); // Image - icon = R.drawable.ic_doc_image; + icon = R.drawable.ic_doc_image_dark; add("application/vnd.oasis.opendocument.graphics", icon); add("application/vnd.oasis.opendocument.graphics-template", icon); add("application/vnd.oasis.opendocument.image", icon); @@ -186,7 +186,7 @@ public class IconUtils { add("application/x-kword", icon); // Video - icon = R.drawable.ic_doc_video; + icon = R.drawable.ic_doc_video_dark; add("application/x-quicktimeplayer", icon); add("application/x-shockwave-flash", icon); } @@ -220,7 +220,7 @@ public class IconUtils { if (mode == DocumentsActivity.State.MODE_GRID) { return res.getDrawable(R.drawable.ic_grid_folder); } else { - return res.getDrawable(R.drawable.ic_root_folder); + return res.getDrawable(R.drawable.ic_root_folder_dark); } } @@ -232,7 +232,7 @@ public class IconUtils { if (Document.MIME_TYPE_DIR.equals(mimeType)) { // TODO: return a mipmap, since this is used for grid - return res.getDrawable(R.drawable.ic_root_folder); + return res.getDrawable(R.drawable.ic_root_folder_dark); } // Look for exact match first @@ -249,13 +249,13 @@ public class IconUtils { // Otherwise look for partial match final String typeOnly = mimeType.split("/")[0]; if ("audio".equals(typeOnly)) { - return res.getDrawable(R.drawable.ic_doc_audio); + return res.getDrawable(R.drawable.ic_doc_audio_dark); } else if ("image".equals(typeOnly)) { - return res.getDrawable(R.drawable.ic_doc_image); + return res.getDrawable(R.drawable.ic_doc_image_dark); } else if ("text".equals(typeOnly)) { return res.getDrawable(R.drawable.ic_doc_text); } else if ("video".equals(typeOnly)) { - return res.getDrawable(R.drawable.ic_doc_video); + return res.getDrawable(R.drawable.ic_doc_video_dark); } else { return res.getDrawable(R.drawable.ic_doc_generic); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java index caa758137215..d06e85889121 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java @@ -103,7 +103,7 @@ public class RootsCache { // Special root for recents mRecentsRoot.authority = null; mRecentsRoot.rootId = null; - mRecentsRoot.icon = R.drawable.ic_root_recent; + mRecentsRoot.icon = R.drawable.ic_root_recent_dark; mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_IS_CHILD; mRecentsRoot.title = mContext.getString(R.string.root_recent); diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java index e220c9e382fb..efa7785105ac 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java @@ -159,15 +159,15 @@ public class RootInfo implements Durable, Parcelable { // TODO: remove these special case icons if (isExternalStorage()) { - derivedIcon = R.drawable.ic_root_sdcard; + derivedIcon = R.drawable.ic_root_sdcard_dark; } else if (isDownloads()) { - derivedIcon = R.drawable.ic_root_download; + derivedIcon = R.drawable.ic_root_download_dark; } else if (isImages()) { - derivedIcon = R.drawable.ic_doc_image; + derivedIcon = R.drawable.ic_doc_image_dark; } else if (isVideos()) { - derivedIcon = R.drawable.ic_doc_video; + derivedIcon = R.drawable.ic_doc_video_dark; } else if (isAudio()) { - derivedIcon = R.drawable.ic_doc_audio; + derivedIcon = R.drawable.ic_doc_audio_dark; } } diff --git a/packages/Keyguard/res/drawable-hdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-hdpi/ic_alarm_small.png Binary files differdeleted file mode 100644 index 381902933dcb..000000000000 --- a/packages/Keyguard/res/drawable-hdpi/ic_alarm_small.png +++ /dev/null diff --git a/packages/Keyguard/res/drawable-mdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-mdpi/ic_alarm_small.png Binary files differdeleted file mode 100644 index 2aeedafbc5ee..000000000000 --- a/packages/Keyguard/res/drawable-mdpi/ic_alarm_small.png +++ /dev/null diff --git a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_alarm_small.png Binary files differdeleted file mode 100644 index e28b3f63367e..000000000000 --- a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_alarm_small.png +++ /dev/null diff --git a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_alarm_small.png Binary files differdeleted file mode 100644 index f727d010696c..000000000000 --- a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_alarm_small.png +++ /dev/null diff --git a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_alarm_small.png Binary files differdeleted file mode 100644 index d9c06234b820..000000000000 --- a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_alarm_small.png +++ /dev/null diff --git a/packages/Keyguard/res/drawable-sw600dp-xxhdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-sw600dp-xxhdpi/ic_alarm_small.png Binary files differdeleted file mode 100644 index a36bf1f2a0ae..000000000000 --- a/packages/Keyguard/res/drawable-sw600dp-xxhdpi/ic_alarm_small.png +++ /dev/null diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-xhdpi/ic_alarm_small.png Binary files differdeleted file mode 100644 index 0290bdc1a94c..000000000000 --- a/packages/Keyguard/res/drawable-xhdpi/ic_alarm_small.png +++ /dev/null diff --git a/packages/Keyguard/res/drawable-xxhdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-xxhdpi/ic_alarm_small.png Binary files differdeleted file mode 100644 index 66968e8e8cd5..000000000000 --- a/packages/Keyguard/res/drawable-xxhdpi/ic_alarm_small.png +++ /dev/null diff --git a/packages/Keyguard/res/drawable/ic_access_alarms_big.xml b/packages/Keyguard/res/drawable/ic_access_alarms_big.xml new file mode 100644 index 000000000000..84ccb7c9fbd6 --- /dev/null +++ b/packages/Keyguard/res/drawable/ic_access_alarms_big.xml @@ -0,0 +1,25 @@ +<!-- +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="18dp" + android:height="18dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + + <path + android:fillColor="@color/clock_gray" + android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/> +</vector> diff --git a/packages/Keyguard/res/drawable/ic_backspace_24dp.xml b/packages/Keyguard/res/drawable/ic_backspace_24dp.xml index 9e5016d991da..47c8d14330c0 100644 --- a/packages/Keyguard/res/drawable/ic_backspace_24dp.xml +++ b/packages/Keyguard/res/drawable/ic_backspace_24dp.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" - android:height="24dp"/> - - <viewport + android:height="24dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#ffffffff" + android:fillColor="#ffffffff" android:pathData="M44.0,6.0L14.0,6.0c-1.4,0.0 -2.5,0.7 -3.2,1.8L0.0,24.0l10.8,16.2c0.7,1.1 1.8,1.8 3.2,1.8l30.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L48.0,10.0C48.0,7.8 46.2,6.0 44.0,6.0zM38.0,31.2L35.2,34.0L28.0,26.8L20.8,34.0L18.0,31.2l7.2,-7.2L18.0,16.8l2.8,-2.8l7.2,7.2l7.2,-7.2l2.8,2.8L30.8,24.0L38.0,31.2z"/> </vector> diff --git a/packages/Keyguard/res/layout/keyguard_status_area.xml b/packages/Keyguard/res/layout/keyguard_status_area.xml index 2730517d4e63..7d8977c8a17d 100644 --- a/packages/Keyguard/res/layout/keyguard_status_area.xml +++ b/packages/Keyguard/res/layout/keyguard_status_area.xml @@ -35,13 +35,11 @@ <TextView android:id="@+id/alarm_status" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:drawablePadding="2dip" - android:drawableLeft="@drawable/ic_alarm_small" - android:drawableStart="@drawable/ic_alarm_small" + android:drawablePadding="6dp" + android:drawableStart="@drawable/ic_access_alarms_big" android:textColor="@color/clock_gray" style="@style/widget_label" - android:layout_marginLeft="8dip" - android:layout_marginStart="8dip" + android:layout_marginStart="6dp" android:gravity="center" android:visibility="gone" /> diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml index 09f521a66a75..1e124b8b1393 100644 --- a/packages/Keyguard/res/values-zh-rCN/strings.xml +++ b/packages/Keyguard/res/values-zh-rCN/strings.xml @@ -22,9 +22,9 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_name" msgid="719438068451601849">"Keyguard"</string> <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入 PIN 码"</string> - <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"请输入 SIM 卡 PUK 码和新的 PIN 码"</string> - <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM 卡 PUK 码"</string> - <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"新 SIM 卡 PIN 码"</string> + <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"请输入SIM卡PUK码和新的 PIN 码"</string> + <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM卡PUK码"</string> + <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"新SIM卡PIN码"</string> <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"触摸可输入密码"</font></string> <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"输入密码以解锁"</string> <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"输入 PIN 进行解锁"</string> @@ -36,16 +36,16 @@ <string name="keyguard_low_battery" msgid="8143808018719173859">"请连接充电器。"</string> <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按“菜单”键解锁。"</string> <string name="keyguard_network_locked_message" msgid="9169717779058037168">"网络已锁定"</string> - <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"无 SIM 卡"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板电脑中没有 SIM 卡。"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手机中没有 SIM 卡。"</string> - <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"请插入 SIM 卡。"</string> - <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM 卡缺失或无法读取,请插入 SIM 卡。"</string> - <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM 卡无法使用。"</string> - <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"您的 SIM 卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张 SIM 卡。"</string> - <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡已被锁定。"</string> - <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡已被 PUK 锁定。"</string> - <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解锁 SIM 卡..."</string> + <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"无SIM卡"</string> + <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板电脑中没有SIM卡。"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手机中没有SIM卡。"</string> + <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"请插入SIM卡。"</string> + <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM卡缺失或无法读取,请插入SIM卡。"</string> + <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM卡无法使用。"</string> + <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"您的SIM卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张SIM卡。"</string> + <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM卡已被锁定。"</string> + <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM卡已被PUK码锁定。"</string> + <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解锁SIM卡..."</string> <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。%3$d的小部件%2$d。"</string> <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"添加小部件。"</string> <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string> @@ -106,16 +106,16 @@ <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 有误"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string> <string name="kg_pattern_instructions" msgid="398978611683075868">"绘制您的图案"</string> - <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入 SIM PIN"</string> + <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入SIM卡PIN码"</string> <string name="kg_pin_instructions" msgid="2377242233495111557">"输入 PIN"</string> <string name="kg_password_instructions" msgid="5753646556186936819">"输入密码"</string> - <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡已被停用,需要输入 PUK 码才能继续使用。有关详情,请联系您的运营商。"</string> + <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM卡已被停用,需要输入PUK码才能继续使用。有关详情,请联系您的运营商。"</string> <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"请输入所需 PIN 码"</string> <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"请确认所需 PIN 码"</string> - <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁 SIM 卡..."</string> + <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁SIM卡..."</string> <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入 4 至 8 位数的 PIN。"</string> - <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 码应至少包含 8 位数字。"</string> - <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的 PUK 码。如果尝试错误次数过多,SIM 卡将永久停用。"</string> + <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK码应至少包含8位数字。"</string> + <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的PUK码。如果尝试错误次数过多,SIM卡将永久停用。"</string> <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 码不匹配"</string> <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string> <string name="kg_login_instructions" msgid="1100551261265506448">"要解锁,请登录您的 Google 帐户。"</string> @@ -136,18 +136,18 @@ <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> + <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM卡PIN码不正确,您现在必须联系运营商为您解锁设备。"</string> <plurals name="kg_password_wrong_pin_code"> - <item quantity="one" msgid="8134313997799638254">"SIM 卡 PIN 码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,则必须联系运营商帮您解锁设备。"</item> - <item quantity="other" msgid="2215723361575359486">"SIM 卡 PIN 码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。"</item> + <item quantity="one" msgid="8134313997799638254">"SIM卡PIN码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,则必须联系运营商帮您解锁设备。"</item> + <item quantity="other" msgid="2215723361575359486">"SIM卡PIN码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。"</item> </plurals> - <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM 卡无法使用,请与您的运营商联系。"</string> + <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM卡无法使用,请与您的运营商联系。"</string> <plurals name="kg_password_wrong_puk_code"> - <item quantity="one" msgid="3256893607561060649">"SIM 卡 PUK 码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM 卡将永远无法使用。"</item> - <item quantity="other" msgid="5477305226026342036">"SIM 卡 PUK 码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM 卡将永远无法使用。"</item> + <item quantity="one" msgid="3256893607561060649">"SIM卡PUK码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将永远无法使用。"</item> + <item quantity="other" msgid="5477305226026342036">"SIM卡PUK码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将永远无法使用。"</item> </plurals> - <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM 卡 PIN 码操作失败!"</string> - <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM 卡 PUK 码操作失败!"</string> + <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM卡PIN码操作失败!"</string> + <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM卡PUK码操作失败!"</string> <string name="kg_pin_accepted" msgid="1448241673570020097">"代码正确!"</string> <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"“上一曲”按钮"</string> <string name="keyguard_transport_next_description" msgid="4299258300283778305">"“下一曲”按钮"</string> diff --git a/packages/Keyguard/res/values/donottranslate.xml b/packages/Keyguard/res/values/donottranslate.xml index 78636dbf2d46..2f544067627e 100644 --- a/packages/Keyguard/res/values/donottranslate.xml +++ b/packages/Keyguard/res/values/donottranslate.xml @@ -18,6 +18,9 @@ <!-- Skeleton string format for displaying the date. --> <string name="abbrev_wday_month_day_no_year">EEEEMMMMd</string> + <!-- Skeleton string format for displaying the date when an alarm is set. --> + <string name="abbrev_wday_month_day_no_year_alarm">EEEMMMMd</string> + <!-- Skeleton string format for displaying the time in 12-hour format. --> <string name="clock_12hr_format">hm</string> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java index 02a441b0ef21..daba0a22598f 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java @@ -71,6 +71,12 @@ public class KeyguardStatusView extends GridLayout { public void onScreenTurnedOff(int why) { setEnableMarquee(false); } + + @Override + public void onUserSwitchComplete(int userId) { + refresh(); + updateOwnerInfo(); + } }; public KeyguardStatusView(Context context) { @@ -110,7 +116,8 @@ public class KeyguardStatusView extends GridLayout { } protected void refresh() { - Patterns.update(mContext); + AlarmClockInfo nextAlarm = mLockPatternUtils.getNextAlarm(); + Patterns.update(mContext, nextAlarm != null); mDateView.setFormat24Hour(Patterns.dateView); mDateView.setFormat12Hour(Patterns.dateView); @@ -118,25 +125,23 @@ public class KeyguardStatusView extends GridLayout { mClockView.setFormat12Hour(Patterns.clockView12); mClockView.setFormat24Hour(Patterns.clockView24); - refreshAlarmStatus(); + refreshAlarmStatus(nextAlarm); } - void refreshAlarmStatus() { - // Update Alarm status - AlarmClockInfo nextAlarm = mLockPatternUtils.getNextAlarm(); + void refreshAlarmStatus(AlarmClockInfo nextAlarm) { if (nextAlarm != null) { - mAlarmStatusView.setText(formatNextAlarm(nextAlarm)); + mAlarmStatusView.setText(formatNextAlarm(mContext, nextAlarm)); mAlarmStatusView.setVisibility(View.VISIBLE); } else { mAlarmStatusView.setVisibility(View.GONE); } } - String formatNextAlarm(AlarmClockInfo info) { + public static String formatNextAlarm(Context context, AlarmClockInfo info) { if (info == null) { return ""; } - String skeleton = DateFormat.is24HourFormat(mContext) ? "EHm" : "Ehma"; + String skeleton = DateFormat.is24HourFormat(context) ? "EHm" : "Ehma"; String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); return DateFormat.format(pattern, info.getTriggerTime()).toString(); } @@ -191,10 +196,12 @@ public class KeyguardStatusView extends GridLayout { static String clockView24; static String cacheKey; - static void update(Context context) { + static void update(Context context, boolean hasAlarm) { final Locale locale = Locale.getDefault(); final Resources res = context.getResources(); - final String dateViewSkel = res.getString(R.string.abbrev_wday_month_day_no_year); + final String dateViewSkel = res.getString(hasAlarm + ? R.string.abbrev_wday_month_day_no_year_alarm + : R.string.abbrev_wday_month_day_no_year); final String clockView12Skel = res.getString(R.string.clock_12hr_format); final String clockView24Skel = res.getString(R.string.clock_24hr_format); final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel; diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index a5dbbcbd7598..f0f5772acccd 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -17,6 +17,7 @@ package com.android.keyguard; import android.app.ActivityManagerNative; +import android.app.AlarmManager; import android.app.IUserSwitchObserver; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; @@ -322,7 +323,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { if (Intent.ACTION_TIME_TICK.equals(action) || Intent.ACTION_TIME_CHANGED.equals(action) - || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { + || Intent.ACTION_TIMEZONE_CHANGED.equals(action) + || AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(action)) { mHandler.sendEmptyMessage(MSG_TIME_UPDATE); } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) { mTelephonyPlmn = getTelephonyPlmnFrom(intent); @@ -568,6 +570,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); context.registerReceiver(mBroadcastReceiver, filter); final IntentFilter bootCompleteFilter = new IntentFilter(); diff --git a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml index f3125f11532c..a7c91058283b 100644 --- a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml +++ b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml @@ -38,6 +38,10 @@ android:label="@string/app_name" android:exported="true" android:launchMode="singleInstance" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> </activity> </application> </manifest> diff --git a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml index 01b107bb4172..06a06bf876b0 100644 --- a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml +++ b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml @@ -17,9 +17,9 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> <Button android:id="@+id/enable_trust" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -28,6 +28,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Revoke trust" /> + <Button android:id="@+id/crash" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Crash" /> <CheckBox android:id="@+id/report_unlock_attempts" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java index 8e293fb01bf3..6b5f78b52ac2 100644 --- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java +++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java @@ -37,6 +37,7 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi findViewById(R.id.enable_trust).setOnClickListener(this); findViewById(R.id.revoke_trust).setOnClickListener(this); + findViewById(R.id.crash).setOnClickListener(this); mReportUnlockAttempts = (CheckBox) findViewById(R.id.report_unlock_attempts); mReportUnlockAttempts.setOnCheckedChangeListener(this); @@ -56,6 +57,8 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi null /* extra */); } else if (id == R.id.revoke_trust) { SampleTrustAgent.sendRevokeTrust(this); + } else if (id == R.id.crash) { + throw new RuntimeException("crash"); } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index 86c3a9237cbe..a1b1aec5003f 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -121,6 +121,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat private static final int STATE_CREATE_FILE_FAILED = 4; private static final int STATE_PRINTER_UNAVAILABLE = 5; private static final int STATE_UPDATE_SLOW = 6; + private static final int STATE_PRINT_COMPLETED = 7; private static final int UI_STATE_PREVIEW = 0; private static final int UI_STATE_ERROR = 1; @@ -304,6 +305,10 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_QUEUED, null); } break; + case STATE_PRINT_COMPLETED: { + spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_COMPLETED, null); + } break; + case STATE_CREATE_FILE_FAILED: { spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_FAILED, getString(R.string.print_write_error_message)); @@ -539,6 +544,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat private void onStartCreateDocumentActivityResult(int resultCode, Intent data) { if (resultCode == RESULT_OK && data != null) { + setState(STATE_PRINT_COMPLETED); + updateOptionsUi(); Uri uri = data.getData(); mPrintedDocument.writeContent(getContentResolver(), uri); // Calling finish here does not invoke lifecycle callbacks but we @@ -706,7 +713,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat private static boolean isFinalState(int state) { return state == STATE_PRINT_CONFIRMED - || state == STATE_PRINT_CANCELED; + || state == STATE_PRINT_CANCELED + || state == STATE_PRINT_COMPLETED; } private void updateSelectedPagesFromPreview() { @@ -1060,6 +1068,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } if (mState == STATE_PRINT_CONFIRMED + || mState == STATE_PRINT_COMPLETED || mState == STATE_PRINT_CANCELED || mState == STATE_UPDATE_FAILED || mState == STATE_CREATE_FILE_FAILED diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png Binary files differdeleted file mode 100644 index 2c5501786d9a..000000000000 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png Binary files differdeleted file mode 100644 index c6dc466729e1..000000000000 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png Binary files differdeleted file mode 100644 index 8bca860052ab..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png Binary files differdeleted file mode 100644 index d42d9d62737d..000000000000 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/ic_access_alarms_small.xml b/packages/SystemUI/res/drawable/ic_access_alarms_small.xml new file mode 100644 index 000000000000..cf64689827f3 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_access_alarms_small.xml @@ -0,0 +1,25 @@ +<!-- +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="16dp" + android:height="16dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + + <path + android:fillColor="#64ffffff" + android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml index 4a4c1c1e2afc..d8649e598e28 100644 --- a/packages/SystemUI/res/drawable/ic_account_circle.xml +++ b/packages/SystemUI/res/drawable/ic_account_circle.xml @@ -13,14 +13,11 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" - android:height="24dp"/> - - <viewport + android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <group android:scaleX="1.2" @@ -28,7 +25,7 @@ Copyright (C) 2014 The Android Open Source Project android:pivotX="12.0" android:pivotY="12.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/> </group> </vector> diff --git a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml b/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml index afcddf1414d2..7b8b89f1814d 100644 --- a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml +++ b/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml @@ -16,14 +16,11 @@ ~ limitations under the License --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" - android:height="24dp"/> - - <viewport + android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <group android:scaleX="1.2" @@ -31,7 +28,7 @@ android:pivotX="12.0" android:pivotY="12.0"> <path - android:fill="@color/qs_user_detail_icon_muted" + android:fillColor="@color/qs_user_detail_icon_muted" android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/> </group> </vector> diff --git a/packages/SystemUI/res/drawable/ic_chevron_left.xml b/packages/SystemUI/res/drawable/ic_chevron_left.xml new file mode 100644 index 000000000000..379382b06504 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_chevron_left.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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="24dp" + android:height="24dp" + android:viewportWidth="36.0" + android:viewportHeight="36.0"> + + <path + android:fillColor="#ffffffff" + android:pathData="M23.1,11.1l-2.1000004,-2.1000004 -9.0,9.0 9.0,9.0 2.1000004,-2.1000004 -6.8999996,-6.8999996z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_clear_all.xml b/packages/SystemUI/res/drawable/ic_clear_all.xml new file mode 100644 index 000000000000..187a420c2bd1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_clear_all.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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="32dp" + android:height="32dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M10.0,26.0l28.0,0.0l0.0,-4.0L10.0,22.0L10.0,26.0zM6.0,34.0l28.0,0.0l0.0,-4.0L6.0,30.0L6.0,34.0zM14.0,14.0l0.0,4.0l28.0,0.0l0.0,-4.0L14.0,14.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_lock_24dp.xml b/packages/SystemUI/res/drawable/ic_lock_24dp.xml index b2e486c0adfe..204af7e81f4c 100644 --- a/packages/SystemUI/res/drawable/ic_lock_24dp.xml +++ b/packages/SystemUI/res/drawable/ic_lock_24dp.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24.0dp" - android:height="24.0dp"/> - - <viewport + android:height="24.0dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="@color/keyguard_affordance" + android:fillColor="@color/keyguard_affordance" android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 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.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml b/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml index 28b16dda7410..c877f063b7a8 100644 --- a/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml +++ b/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24.0dp" - android:height="24.0dp"/> - - <viewport + android:height="24.0dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="@color/keyguard_affordance" + android:fillColor="@color/keyguard_affordance" android:pathData="M12.0,17.0c1.1,0.0 2.0,-0.9 2.0,-2.0s-0.9,-2.0 -2.0,-2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0S10.9,17.0 12.0,17.0zM18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l1.9,0.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM18.0,20.0L6.0,20.0L6.0,10.0l12.0,0.0L18.0,20.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml b/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml index e5737ee3d948..2d779499f6e6 100644 --- a/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml +++ b/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24.0dp" - android:height="24.0dp"/> - - <viewport + android:height="24.0dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="@color/recents_task_view_lock_to_app_button_color" + android:fillColor="@color/recents_task_view_lock_to_app_button_color" android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 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.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_power_low.xml b/packages/SystemUI/res/drawable/ic_power_low.xml index 5bb7aba6fa74..ba99948a5737 100644 --- a/packages/SystemUI/res/drawable/ic_power_low.xml +++ b/packages/SystemUI/res/drawable/ic_power_low.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24.0dp" - android:height="24.0dp"/> - - <viewport + android:height="24.0dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM26.0,37.0l-4.0,0.0l0.0,-4.0l4.0,0.0L26.0,37.0zM26.0,30.0l-4.0,0.0L22.0,15.0l4.0,0.0L26.0,30.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_power_saver.xml b/packages/SystemUI/res/drawable/ic_power_saver.xml index 26e7375d01bd..2162d79e7b8f 100644 --- a/packages/SystemUI/res/drawable/ic_power_saver.xml +++ b/packages/SystemUI/res/drawable/ic_power_saver.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24.0dp" - android:height="24.0dp"/> - - <viewport + android:height="24.0dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM32.0,28.0l-6.0,0.0l0.0,6.0l-4.0,0.0l0.0,-6.0l-6.0,0.0l0.0,-4.0l6.0,0.0l0.0,-6.0l4.0,0.0l0.0,6.0l6.0,0.0L32.0,28.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml b/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml index c68238f24d20..79a9d409e687 100644 --- a/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml +++ b/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M26.0,18.0L26.0,7.0c0.0,-1.7 -1.3,-3.0 -3.0,-3.0c-1.7,0.0 -3.0,1.3 -3.0,3.0l0.0,7.4L35.7,30.0l6.3,2.0l0.0,-4.0L26.0,18.0zM6.0,10.5l10.0,10.0L4.0,28.0l0.0,4.0l16.0,-5.0l0.0,11.0l-4.0,3.0l0.0,3.0l7.0,-2.0l7.0,2.0l0.0,-3.0l-4.0,-3.0l0.0,-7.5L37.5,42.0l2.5,-2.5L8.5,8.0L6.0,10.5z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml b/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml index c1e3c7e9a805..5d5d2576c6cd 100644 --- a/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml +++ b/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml @@ -13,19 +13,16 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M20.4,18.0"/> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M42.0,32.0l0.0,-4.0L26.0,18.0L26.0,7.0c0.0,-1.7 -1.3,-3.0 -3.0,-3.0c-1.7,0.0 -3.0,1.3 -3.0,3.0l0.0,11.0L4.0,28.0l0.0,4.0l16.0,-5.0l0.0,11.0l-4.0,3.0l0.0,3.0l7.0,-2.0l7.0,2.0l0.0,-3.0l-4.0,-3.0L26.0,27.0L42.0,32.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_back.xml b/packages/SystemUI/res/drawable/ic_qs_back.xml index 52039f588cd2..f00ba03eb829 100644 --- a/packages/SystemUI/res/drawable/ic_qs_back.xml +++ b/packages/SystemUI/res/drawable/ic_qs_back.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M20.0,11.0L7.8,11.0l5.6,-5.6L12.0,4.0l-8.0,8.0l8.0,8.0l1.4,-1.4L7.8,13.0L20.0,13.0L20.0,11.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml index 3957d02fdefd..0c65389349ae 100644 --- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml +++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M14.0,24.0l-4.0,-4.0l-4.0,4.0l4.0,4.0L14.0,24.0zM35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6zM38.0,20.0l-4.0,4.0l4.0,4.0l4.0,-4.0L38.0,20.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml index e4038f9d66d2..b9a315cd74e3 100644 --- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml +++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M28.5,24.0l4.6,4.6c0.6,-1.4 0.9,-3.0 0.9,-4.7c0.0,-1.6 -0.3,-3.2 -0.9,-4.6L28.5,24.0zM39.1,13.4L36.5,16.0c1.3,2.4 2.0,5.1 2.0,8.0s-0.7,5.6 -2.0,8.0l2.4,2.4c1.9,-3.1 3.1,-6.7 3.1,-10.6C42.0,20.0 40.9,16.5 39.1,13.4zM31.4,15.4L20.0,4.0l-2.0,0.0l0.0,15.2L8.8,10.0L6.0,12.8L17.2,24.0L6.0,35.2L8.8,38.0l9.2,-9.2L18.0,44.0l2.0,0.0l11.4,-11.4L22.8,24.0L31.4,15.4zM22.0,11.7l3.8,3.8L22.0,19.2L22.0,11.7zM25.8,32.6L22.0,36.3l0.0,-7.5L25.8,32.6z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml index aa0b36964808..dd92126a6dc7 100644 --- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml +++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="56dp" - android:height="56dp"/> - - <viewport + android:height="56dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="@color/qs_detail_empty" + android:fillColor="@color/qs_detail_empty" android:pathData="M35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml index 00c5af8a2ecf..0cb1f32acb39 100644 --- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml +++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M26.0,11.8l3.8,3.8l-3.2,3.2l2.8,2.8l6.0,-6.0L24.0,4.2l-2.0,0.0l0.0,10.1l4.0,4.0L26.0,11.8zM10.8,8.2L8.0,11.0l13.2,13.2L10.0,35.3l2.8,2.8L22.0,29.0l0.0,15.2l2.0,0.0l8.6,-8.6l4.6,4.6l2.8,-2.8L10.8,8.2zM26.0,36.5L26.0,29.0l3.8,3.8L26.0,36.5z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml index 2b14f33ab514..9a68dad159ef 100644 --- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml +++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml index 29588480a749..0df1a9626ffc 100644 --- a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml +++ b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_cancel.xml b/packages/SystemUI/res/drawable/ic_qs_cancel.xml index de72f130a3e4..e4f4174b9ca1 100644 --- a/packages/SystemUI/res/drawable/ic_qs_cancel.xml +++ b/packages/SystemUI/res/drawable/ic_qs_cancel.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" - android:height="24dp"/> - - <viewport + android:height="24dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M24.0,4.0C12.9,4.0 4.0,12.9 4.0,24.0s8.9,20.0 20.0,20.0c11.1,0.0 20.0,-8.9 20.0,-20.0S35.1,4.0 24.0,4.0zM34.0,31.2L31.2,34.0L24.0,26.8L16.8,34.0L14.0,31.2l7.2,-7.2L14.0,16.8l2.8,-2.8l7.2,7.2l7.2,-7.2l2.8,2.8L26.8,24.0L34.0,31.2z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml index fbc21d4a4331..59dcea2337cb 100644 --- a/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml +++ b/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="56dp" - android:height="56dp"/> - - <viewport + android:height="56dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="@color/qs_detail_empty" + android:fillColor="@color/qs_detail_empty" android:pathData="M42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0zM2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml index 2a9541e493a1..80517958dac2 100644 --- a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml +++ b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0zM2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml index 159bf65256c9..794eb9e6bd58 100644 --- a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml +++ b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM38.0,14.0L10.0,14.0l0.0,3.3c7.9,2.6 14.2,8.8 16.7,16.7L38.0,34.0L38.0,14.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0zM42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml b/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml index 0f30be2a5a7b..d4bd76fbc8a6 100644 --- a/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml +++ b/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml @@ -13,22 +13,19 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64.0dp" - android:height="64.0dp"/> - - <viewport + android:height="64.0dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M14.708,11.394l14.899,14.9l0.0,-6.771c4.359,-2.353 3.831,-7.489 3.831,-7.489l0.0,-0.64L14.708,11.393998z"/> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M14.568,4.0l18.87,0.0l0.0,3.917l-18.87,0.0z"/> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M38.284,39.427l-29.767,-29.766998 -2.4750004,2.4750004 12.351999,12.351 0.0,19.514 11.213001,0.0 0.0,-8.300999 6.2019978,6.2019997z"/> </vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml b/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml index 2e9d40131446..5514b44c1481 100644 --- a/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml +++ b/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml @@ -13,19 +13,16 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64.0dp" - android:height="64.0dp"/> - - <viewport + android:height="64.0dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M33.438,12.034l0.0,-0.64l-18.87,0.0l0.0,0.64c0.0,0.0 -0.581,5.189 3.826,7.523L18.394,44.0l11.213,0.0L29.606998,19.523C33.966,17.17 33.438,12.034 33.438,12.034zM24.0,27.697c-1.523,0.0 -2.757,-1.234 -2.757,-2.757c0.0,-1.523 1.234,-2.757 2.757,-2.757c1.523,0.0 2.757,1.234 2.757,2.757C26.757,26.462 25.523,27.697 24.0,27.697z"/> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M14.568,4.0l18.87,0.0l0.0,3.917l-18.87,0.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml index 0a00d14c8aeb..d68ee4c2f65b 100644 --- a/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml +++ b/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml @@ -13,16 +13,12 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64.0dp" - android:height="64.0dp"/> - - <viewport + android:height="64.0dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> - + android:viewportHeight="48.0"> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M35.099998,28.500000c0.600000,-1.400000 0.900000,-2.900000 0.900000,-4.500000c0.000000,-6.600000 -5.400000,-12.000000 -12.000000,-12.000000c-1.600000,0.000000 -3.100000,0.300000 -4.500000,0.900000l3.200000,3.200000c0.400000,-0.100000 0.800000,-0.100000 1.200000,-0.100000c4.400000,0.000000 8.000000,3.600000 8.000000,8.000000c0.000000,0.400000 0.000000,0.800000 -0.100000,1.300000L35.099998,28.500000zM24.000000,8.000000c8.800000,0.000000 16.000000,7.200000 16.000000,16.000000c0.000000,2.700000 -0.700000,5.200000 -1.900000,7.500000l2.900000,2.900000c1.900000,-3.000000 3.000000,-6.600000 3.000000,-10.400000c0.000000,-11.000000 -9.000000,-20.000000 -20.000000,-20.000000c-3.800000,0.000000 -7.400000,1.100000 -10.400000,2.900000l2.900000,2.900000C18.700001,8.700000 21.299999,8.000000 24.000000,8.000000zM6.500000,5.000000L4.000000,7.500000l4.200000,4.200000C5.600000,15.100000 4.000000,19.400000 4.000000,24.000000c0.000000,7.400000 4.000000,13.800000 10.000000,17.299999l2.000000,-3.500000c-4.800000,-2.800000 -8.000000,-7.900000 -8.000000,-13.800000c0.000000,-3.500000 1.100000,-6.800000 3.100000,-9.400000l2.900000,2.900000C12.700000,19.400000 12.000000,21.600000 12.000000,24.000000c0.000000,4.400000 2.400000,8.300000 6.000000,10.400000l2.000000,-3.500000c-2.400000,-1.400000 -4.000000,-3.900000 -4.000000,-6.900000c0.000000,-1.300000 0.300000,-2.500000 0.900000,-3.600000l3.200000,3.200000c0.000000,0.100000 0.000000,0.300000 0.000000,0.400000c0.000000,2.200000 1.800000,4.000000 4.000000,4.000000c0.100000,0.000000 0.300000,0.000000 0.400000,0.000000l0.000000,0.000000l0.000000,0.000000l15.000000,15.000000l2.500000,-2.500000L8.500000,7.000000L6.500000,5.000000z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml index 01cb0ab3c544..da09f6e39f4e 100644 --- a/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml +++ b/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64.0dp" - android:height="64.0dp"/> - - <viewport + android:height="64.0dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M24.000000,22.000000c-2.200000,0.000000 -4.000000,1.800000 -4.000000,4.000000c0.000000,2.200000 1.800000,4.000000 4.000000,4.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000C28.000000,23.799999 26.200001,22.000000 24.000000,22.000000zM36.000000,26.000000c0.000000,-6.600000 -5.400000,-12.000000 -12.000000,-12.000000c-6.600000,0.000000 -12.000000,5.400000 -12.000000,12.000000c0.000000,4.400000 2.400000,8.300000 6.000000,10.400000l2.000000,-3.500000c-2.400000,-1.400000 -4.000000,-3.900000 -4.000000,-6.900000c0.000000,-4.400000 3.600000,-8.000000 8.000000,-8.000000s8.000000,3.600000 8.000000,8.000000c0.000000,3.000000 -1.600000,5.500000 -4.000000,6.900000l2.000000,3.500000C33.599998,34.299999 36.000000,30.400000 36.000000,26.000000zM24.000000,6.000000C13.000000,6.000000 4.000000,15.000000 4.000000,26.000000c0.000000,7.400000 4.000000,13.800000 10.000000,17.299999l2.000000,-3.500000c-4.800000,-2.800000 -8.000000,-7.900000 -8.000000,-13.800000c0.000000,-8.800000 7.200000,-16.000000 16.000000,-16.000000s16.000000,7.200000 16.000000,16.000000c0.000000,5.900000 -3.200000,11.100000 -8.000000,13.800000l2.000000,3.500000c6.000000,-3.500000 10.000000,-9.900000 10.000000,-17.299999C44.000000,15.000000 35.000000,6.000000 24.000000,6.000000z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml index b6a5cadfe0c8..4237b63c5eb4 100644 --- a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml +++ b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M41.3,41.7L36.6,37.0L24.0,24.5l-7.1,-7.1L14.0,14.5L8.5,9.0L6.0,11.5l5.6,5.6c-5.1,6.3 -4.7,15.5 1.1,21.4c3.1,3.1 7.2,4.7 11.3,4.7c3.6,0.0 7.1,-1.2 10.1,-3.6l5.4,5.4l2.5,-2.5L41.3,41.7zM24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5c0.0,-2.6 0.9,-5.1 2.4,-7.2l9.6,9.6L24.0,39.2zM24.0,10.2l0.0,9.2l14.5,14.5c2.7,-5.9 1.7,-13.1 -3.2,-18.0L24.0,4.5l0.0,0.0l0.0,0.0L16.6,12.0l2.8,2.8L24.0,10.2z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml index e8d59e0dad9d..860e76963f5e 100644 --- a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml +++ b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M35.3,15.9L24.0,4.5l0.0,0.0l0.0,0.0L12.7,15.9c-6.2,6.2 -6.2,16.4 0.0,22.6c3.1,3.1 7.2,4.7 11.3,4.7s8.2,-1.6 11.3,-4.7C41.6,32.2 41.6,22.1 35.3,15.9zM24.0,39.2L24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5s1.2,-6.2 3.5,-8.5l8.5,-8.5L24.0,39.2z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_location_off.xml b/packages/SystemUI/res/drawable/ic_qs_location_off.xml index 26ebfbf050b1..e0fe12ee2fe0 100644 --- a/packages/SystemUI/res/drawable/ic_qs_location_off.xml +++ b/packages/SystemUI/res/drawable/ic_qs_location_off.xml @@ -13,19 +13,16 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M24.0,13.0c2.8,0.0 5.0,2.2 5.0,5.0c0.0,1.5 -0.7,2.8 -1.7,3.7l7.3,7.3c2.0,-3.7 3.4,-7.6 3.4,-11.0c0.0,-7.7 -6.3,-14.0 -14.0,-14.0c-4.0,0.0 -7.5,1.6 -10.1,4.3l6.4,6.4C21.2,13.6 22.5,13.0 24.0,13.0zM32.7,32.2l-9.3,-9.3l-0.2,-0.2L6.5,6.0L4.0,8.5l6.4,6.4c-0.2,1.0 -0.4,2.0 -0.4,3.1c0.0,10.5 14.0,26.0 14.0,26.0s3.3,-3.7 6.8,-8.7l6.7,6.7l2.5,-2.5L32.7,32.2z"/> <path android:pathData="M23.5,22.9l0.0,0.0 -0.20000076,-0.19999886z" - android:fill="#4DFFFFFF"/> + android:fillColor="#4DFFFFFF"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_location_on.xml b/packages/SystemUI/res/drawable/ic_qs_location_on.xml index bc73005ff891..6a7cd53930fe 100644 --- a/packages/SystemUI/res/drawable/ic_qs_location_on.xml +++ b/packages/SystemUI/res/drawable/ic_qs_location_on.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M24.0,4.0c-7.7,0.0 -14.0,6.3 -14.0,14.0c0.0,10.5 14.0,26.0 14.0,26.0s14.0,-15.5 14.0,-26.0C38.0,10.3 31.7,4.0 24.0,4.0zM24.0,23.0c-2.8,0.0 -5.0,-2.2 -5.0,-5.0s2.2,-5.0 5.0,-5.0c2.8,0.0 5.0,2.2 5.0,5.0S26.8,23.0 24.0,23.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml index 7b76e0f4d56e..4722c9edcc40 100644 --- a/packages/SystemUI/res/drawable/ic_qs_minus.xml +++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" - android:height="24dp"/> - - <viewport + android:height="24dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0L14.0,26.0l0.0,-4.0l20.0,0.0L34.0,26.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml index 4b9f5062a993..17d74cfec136 100644 --- a/packages/SystemUI/res/drawable/ic_qs_plus.xml +++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" - android:height="24dp"/> - - <viewport + android:height="24dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0l-8.0,0.0l0.0,8.0l-4.0,0.0l0.0,-8.0l-8.0,0.0l0.0,-4.0l8.0,0.0l0.0,-8.0l4.0,0.0l0.0,8.0l8.0,0.0L34.0,26.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml index 787eec551715..9c5983d4d6e4 100644 --- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml +++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml index dd6be76093d0..904ccdfb70ad 100644 --- a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml +++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml index 96d20e8ecb9b..a23c6f0afa9c 100644 --- a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml +++ b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml index e4c7cb589f49..4bb3668f9108 100644 --- a/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml +++ b/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M2.0,14.0l0.0,20.0c0.0,2.2 1.8,4.0 4.0,4.0l36.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,14.0c0.0,-2.2 -1.8,-4.0 -4.0,-4.0L6.0,10.0C3.8,10.0 2.0,11.8 2.0,14.0zM38.0,14.0l0.0,20.0L10.0,34.0L10.0,14.0L38.0,14.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml index e4bf367db694..f0878c711364 100644 --- a/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml +++ b/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M34.0,2.0L14.0,2.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,36.0c0.0,2.2 1.8,4.0 4.0,4.0l20.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L38.0,6.0C38.0,3.8 36.2,2.0 34.0,2.0zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0L34.0,38.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml index a6c2cf8c2f7e..6872a33198cb 100644 --- a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml +++ b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml @@ -13,22 +13,19 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M10.25,1.75c-0.6,-0.6 -1.5,-0.6 -2.1,0.0l-6.4,6.4c-0.6,0.6 -0.6,1.5 0.0,2.1l12.0,12.0c0.6,0.6 1.5,0.6 2.1,0.0l6.4,-6.4c0.6,-0.6 0.6,-1.5 0.0,-2.1L10.25,1.75zM14.85,21.25l-12.0,-12.0l6.4,-6.4l12.0,12.0L14.85,21.25z"/> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M16.55,2.5c3.3,1.5 5.6,4.7 6.0,8.5l1.5,0.0c-0.6,-6.2 -5.7,-11.0 -12.0,-11.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.55,2.5z"/> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M7.55,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5l-1.4,0.0c0.5,6.2 5.6,11.0 11.9,11.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.55,21.5z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml index 16fa30bbc9b9..ad6b247490d1 100644 --- a/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml +++ b/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="56dp" - android:height="56dp"/> - - <viewport + android:height="56dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path android:pathData="M24.0,4.0C15.0,4.0 6.7,7.0 0.0,12.0l24.0,32.0l24.0,-32.0C41.3,7.0 33.0,4.0 24.0,4.0z" - android:fill="@color/qs_detail_empty" /> + android:fillColor="@color/qs_detail_empty" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_ringer_audible.xml index 296994825b1f..f358fa2e39a8 100644 --- a/packages/SystemUI/res/drawable/ic_ringer_audible.xml +++ b/packages/SystemUI/res/drawable/ic_ringer_audible.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" - android:height="32dp"/> - - <viewport + android:height="32dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml index d8ded5844dc4..9642be308f5c 100644 --- a/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml +++ b/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" - android:height="32dp"/> - - <viewport + android:height="32dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml index a2f78225b77b..9c7874215cf7 100644 --- a/packages/SystemUI/res/drawable/ic_settings_24dp.xml +++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml @@ -12,18 +12,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > -<size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" -android:height="24dp"/> - - <viewport android:viewportWidth="24.0" - android:viewportHeight="24.0"/> +android:height="24dp" android:viewportWidth="24.0" + android:viewportHeight="24.0"> <path android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z" - android:fill="#ffffffff" + android:fillColor="#ffffffff" /> </vector> diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml new file mode 100644 index 000000000000..07932d1af054 --- /dev/null +++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2014 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/notification_guts_bg_color" /> + <corners android:radius="@dimen/notification_material_rounded_rect_radius" /> +</shape> diff --git a/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml b/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml index 9137e7f6a0b9..71400dbedc6a 100644 --- a/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml +++ b/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24.0dp" - android:height="24.0dp"/> - - <viewport + android:height="24.0dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="@color/qs_tile_text" + android:fillColor="@color/qs_tile_text" android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/qs_subhead_caret.xml b/packages/SystemUI/res/drawable/qs_subhead_caret.xml index f140bd0adda4..13a168d758aa 100644 --- a/packages/SystemUI/res/drawable/qs_subhead_caret.xml +++ b/packages/SystemUI/res/drawable/qs_subhead_caret.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24.0dp" - android:height="24.0dp"/> - - <viewport + android:height="24.0dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="@color/qs_subhead" + android:fillColor="@color/qs_subhead" android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml index 9c1165de6175..337c028b77c8 100644 --- a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml +++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml @@ -13,20 +13,16 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android"> - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="16dp" - android:width="16dp" /> - - <viewport + android:width="16dp" android:viewportHeight="100" - android:viewportWidth="100" /> + android:viewportWidth="100" > <path android:name="x" android:pathData="M0,0L100,100M0,100L100,0z" - android:stroke="@color/recents_task_bar_dark_dismiss_color" + android:strokeColor="@color/recents_task_bar_dark_dismiss_color" android:strokeWidth="8.0" android:strokeLineCap="square" /> diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml index a8afeb313435..963ccf7be00d 100644 --- a/packages/SystemUI/res/drawable/recents_dismiss_light.xml +++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml @@ -13,21 +13,17 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android"> - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="16dp" - android:width="16dp" /> - - <viewport + android:width="16dp" android:viewportHeight="100" - android:viewportWidth="100" /> + android:viewportWidth="100" > <path android:name="x" android:pathData="M0,0L100,100M0,100L100,0z" - android:stroke="@color/recents_task_bar_light_dismiss_color" + android:strokeColor="@color/recents_task_bar_light_dismiss_color" android:strokeWidth="8.0" android:strokeLineCap="square" /> diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm.xml b/packages/SystemUI/res/drawable/stat_sys_alarm.xml new file mode 100644 index 000000000000..3b2bc31ff4c2 --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_alarm.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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="18dp" + android:height="18dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + + <path + android:fillColor="#ffffffff" + android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml index e28490bfb890..f53f0e4729df 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="18dp" - android:height="18dp"/> - - <viewport + android:height="18dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6z"/> </vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml index c012d14a7fba..2aac4ee03c3c 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="18dp" - android:height="18dp"/> - - <viewport + android:height="18dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M14.0,24.0l-4.0,-4.0l-4.0,4.0l4.0,4.0L14.0,24.0zM35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6zM38.0,20.0l-4.0,4.0l4.0,4.0l4.0,-4.0L38.0,20.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_no_sim.xml b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml index 70948b7f4d5f..22d1d4b8beac 100644 --- a/packages/SystemUI/res/drawable/stat_sys_no_sim.xml +++ b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="18dp" - android:height="18dp"/> - - <viewport + android:height="18dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#4DFFFFFF" + android:fillColor="#4DFFFFFF" android:pathData="M19.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-7.0,0.0L7.7,5.3L19.0,16.7L19.0,5.0zM3.7,3.9L2.4,5.2L5.0,7.8L5.0,19.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c0.4,0.0 0.7,-0.1 1.0,-0.3l1.9,1.9l1.3,-1.3L3.7,3.9z"/> </vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml index e1d63c374358..352d86ff8c66 100644 --- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml +++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" - android:height="20dp"/> - - <viewport + android:height="20dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml index 54a9b1b61a36..73d7cba56b19 100644 --- a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml +++ b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" - android:height="20dp"/> - - <viewport + android:height="20dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportHeight="24.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M12.0,17.273l6.1800003,3.7269993 -1.6350002,-7.0290003 5.455,-4.7269993 -7.191,-0.6170006 -2.809,-6.627 -2.809,6.627 -7.191,0.6170006 5.455,4.7269993 -1.6349998,7.0290003z"/> </vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml b/packages/SystemUI/res/drawable/stat_sys_zen_none.xml index 101e3c467c96..d8ab078c14a8 100644 --- a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml +++ b/packages/SystemUI/res/drawable/stat_sys_zen_none.xml @@ -13,16 +13,13 @@ Copyright (C) 2014 The Android Open Source Project See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="19dp" - android:height="19dp"/> - - <viewport + android:height="19dp" android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportHeight="48.0"> <path - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0C44.0,13.0 35.0,4.0 24.0,4.0zM24.0,40.0c-8.8,0.0 -16.0,-7.2 -16.0,-16.0c0.0,-3.7 1.3,-7.1 3.4,-9.8l22.4,22.4C31.1,38.7 27.7,40.0 24.0,40.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8z"/> </vector> diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index db5983bda12f..f8315702cdd8 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -22,7 +22,24 @@ android:layout_height="match_parent" android:layout_width="match_parent" > - <com.android.systemui.statusbar.AlphaImageView + + <com.android.systemui.statusbar.phone.KeyguardIndicationTextView + android:id="@+id/keyguard_indication_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="70dp" + android:layout_gravity="bottom|center_horizontal" + android:textStyle="italic" + android:textColor="#ffffff" + android:textAppearance="?android:attr/textAppearanceSmall"/> + + <FrameLayout + android:id="@+id/preview_container" + android:layout_width="match_parent" + android:layout_height="match_parent"> + </FrameLayout> + + <com.android.systemui.statusbar.KeyguardAffordanceView android:id="@+id/camera_button" android:layout_height="64dp" android:layout_width="64dp" @@ -32,7 +49,7 @@ android:scaleType="center" android:contentDescription="@string/accessibility_camera_button" /> - <com.android.systemui.statusbar.AlphaImageView + <com.android.systemui.statusbar.KeyguardAffordanceView android:id="@+id/phone_button" android:layout_height="64dp" android:layout_width="64dp" @@ -42,17 +59,7 @@ android:scaleType="center" android:contentDescription="@string/accessibility_phone_button" /> - <com.android.systemui.statusbar.phone.KeyguardIndicationTextView - android:id="@+id/keyguard_indication_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="70dp" - android:layout_gravity="bottom|center_horizontal" - android:textStyle="italic" - android:textColor="#ffffff" - android:textAppearance="?android:attr/textAppearanceSmall"/> - - <com.android.systemui.statusbar.AlphaImageView + <com.android.systemui.statusbar.KeyguardAffordanceView android:id="@+id/lock_icon" android:layout_width="64dp" android:layout_height="64dp" diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml new file mode 100644 index 000000000000..0e78d669a136 --- /dev/null +++ b/packages/SystemUI/res/layout/notification_guts.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 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. +--> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/notification_guts_bg" + android:id="@+id/notification_guts" + android:visibility="gone" + android:clickable="true" + android:gravity="top|start" + > + <LinearLayout + android:layout_width="match_parent" + android:layout_height="@android:dimen/notification_large_icon_height" + android:orientation="horizontal" + > + + <ImageView android:id="@android:id/icon" + android:layout_width="@android:dimen/notification_large_icon_width" + android:layout_height="@android:dimen/notification_large_icon_height" + android:layout_weight="0" + android:padding="8dp" + android:scaleType="centerInside" + /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="start|center_vertical" + android:orientation="vertical" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:layout_weight="1" + > + <TextView + android:id="@+id/pkgname" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical|start" + android:layout_weight="1" + android:textAppearance="@*android:style/TextAppearance.StatusBar.Material.EventContent.Title" + android:textColor="@color/notification_guts_title_color" + /> + <DateTimeView + android:id="@+id/timestamp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:layout_gravity="center_vertical|start" + android:textAppearance="@*android:style/TextAppearance.StatusBar.Material.EventContent.Time" + android:textColor="@color/notification_guts_text_color" + /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/debug_info" + android:layout_weight="0" + android:textAppearance="@*android:style/TextAppearance.StatusBar.Material.EventContent.Time" + android:layout_gravity="bottom|start" + android:visibility="gone" + android:textColor="@color/notification_guts_text_color" + /> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:layout_weight="0" + android:orientation="horizontal" + android:showDividers="beginning|middle" + android:divider="@*android:drawable/list_divider_holo_dark" + android:dividerPadding="8dp" + > + <Button style="@android:style/Widget.Material.Light.Button.Borderless.Small" + android:id="@+id/notification_inspect_item" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="start|center_vertical" + android:drawablePadding="8dp" + android:paddingStart="8dp" + android:textColor="@color/notification_guts_btn_color" + android:textSize="14dp" + android:singleLine="true" + android:ellipsize="end" + android:text="@string/status_bar_notification_inspect_item_title" + /> + </LinearLayout> + </LinearLayout> +</FrameLayout> diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 595d731d56d0..19dc36ddda05 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -87,7 +87,8 @@ android:layout_height="match_parent" android:gravity="center_vertical" > - <LinearLayout android:id="@+id/statusIcons" + <com.android.systemui.statusbar.AlphaOptimizedLinearLayout + android:id="@+id/statusIcons" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center_vertical" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 1f68cd822f14..9af2879f9ebb 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -56,14 +56,6 @@ android:clipToPadding="false" android:clipChildren="false"> - <ViewStub - android:id="@+id/keyguard_user_switcher" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_marginTop="@dimen/status_bar_header_height_keyguard" - android:layout_gravity="end" - android:layout="@layout/keyguard_user_switcher" /> - <com.android.systemui.statusbar.phone.ObservableScrollView android:id="@+id/scroll_view" android:layout_width="match_parent" @@ -103,6 +95,14 @@ android:layout_height="match_parent" android:layout_marginBottom="@dimen/close_handle_underlap"/> + <ViewStub + android:id="@+id/keyguard_user_switcher" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_marginTop="@dimen/status_bar_header_height_keyguard" + android:layout_gravity="end" + android:layout="@layout/keyguard_user_switcher" /> + </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer> <include layout="@layout/status_bar_expanded_header" /> diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 272904a6182d..b260a4a28d79 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -68,7 +68,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:layout_marginStart="8dp" + android:layout_marginStart="@dimen/header_battery_margin_keyguard" android:paddingEnd="@dimen/battery_level_padding_end" android:textColor="#ffffff" android:textSize="12sp"/> @@ -87,24 +87,16 @@ android:text="@*android:string/emergency_calls_only" android:gravity="center_vertical" /> - <RelativeLayout - android:id="@+id/datetime" + <FrameLayout + android:id="@+id/date_group" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="start" - android:paddingTop="4dp" - android:paddingStart="16dp" - android:paddingEnd="16dp" - android:background="?android:attr/selectableItemBackground" - android:enabled="false" - > - <include layout="@layout/split_clock_view" - android:id="@+id/clock" - /> - + android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin" + android:layout_alignParentBottom="true"> <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginStart="16dp" android:singleLine="true" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" android:layout_below="@id/clock" @@ -113,17 +105,45 @@ <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_expanded" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginStart="16dp" android:singleLine="true" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" android:layout_below="@id/clock" systemui:datePattern="eeeeMMMMd" /> - </RelativeLayout> + </FrameLayout> + + <include layout="@layout/split_clock_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_above="@id/date_group" + android:id="@+id/clock" + /> + + <Button android:id="@+id/alarm_status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_toEndOf="@id/date_group" + android:layout_marginBottom="4dp" + android:drawablePadding="6dp" + android:drawableStart="@drawable/ic_access_alarms_small" + android:textColor="#64ffffff" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" + android:paddingEnd="6dp" + android:paddingStart="6dp" + android:paddingTop="16dp" + android:paddingBottom="16dp" + android:background="?android:attr/selectableItemBackground" + android:visibility="gone" + /> + <com.android.keyguard.CarrierText android:id="@+id/keyguard_carrier_text" android:layout_width="match_parent" android:layout_height="@dimen/status_bar_header_height_keyguard" - android:layout_marginLeft="16dp" + android:layout_marginStart="@dimen/keyguard_carrier_text_margin" android:layout_toStartOf="@id/system_icons_super_container" android:gravity="center_vertical" android:ellipsize="marquee" diff --git a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml new file mode 100644 index 000000000000..515270a97292 --- /dev/null +++ b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml @@ -0,0 +1,40 @@ +<!-- + ~ 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 + --> + +<!-- Extends Framelayout --> +<com.android.systemui.statusbar.DismissView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone" + > + <Button + android:id="@+id/dismiss_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="0dp" + android:textColor="#ffffffff" + android:text="@string/clear_all_notifications_text" + android:textSize="18sp" + android:textAllCaps="true" + android:paddingTop="@dimen/clear_all_padding_top" + android:paddingEnd="8dp" + android:layout_gravity="end|center_vertical" + android:drawableEnd="@drawable/ic_clear_all" + android:drawablePadding="4dp" + android:fontFamily="sans-serif-light" + android:background="@drawable/ripple_drawable" /> +</com.android.systemui.statusbar.DismissView> diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml index 7663d54a2498..ef4e27ce3243 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_row.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml @@ -1,3 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2014, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + <com.android.systemui.statusbar.ExpandableNotificationRow xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" @@ -35,17 +52,11 @@ android:paddingStart="8dp" /> - <TextView - android:id="@+id/debug_info" - android:visibility="invisible" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|end" - android:fontFamily="sans-serif-condensed" - android:textSize="9dp" - android:textStyle="bold" - android:textColor="#00A040" - android:padding="2dp" + <include + layout="@layout/notification_guts" + android:id="@+id/notification_guts" + android:layout_width="match_parent" + android:layout_height="match_parent" /> <com.android.systemui.statusbar.NotificationScrimView diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index e3ac1c1cdde6..ac998f69ca0d 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -26,7 +26,7 @@ android:fitsSystemWindows="true" android:descendantFocusability="afterDescendants"> - <FrameLayout + <com.android.systemui.statusbar.AlphaOptimizedFrameLayout android:id="@+id/backdrop" android:layout_width="match_parent" android:layout_height="match_parent" @@ -41,7 +41,7 @@ android:layout_height="match_parent" android:scaleType="centerCrop" android:visibility="invisible" /> - </FrameLayout> + </com.android.systemui.statusbar.AlphaOptimizedFrameLayout> <View android:id="@+id/scrim_behind" android:layout_width="match_parent" @@ -54,7 +54,8 @@ <com.android.systemui.statusbar.phone.PanelHolder android:id="@+id/panel_holder" android:layout_width="match_parent" - android:layout_height="match_parent" > + android:layout_height="match_parent" + android:background="@color/transparent" > <include layout="@layout/status_bar_expanded" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/menu/notification_popup_menu.xml b/packages/SystemUI/res/menu/notification_popup_menu.xml deleted file mode 100644 index 8923fb67ff0e..000000000000 --- a/packages/SystemUI/res/menu/notification_popup_menu.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* apps/common/assets/default/default/skins/StatusBar.xml -** -** Copyright 2012, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> -<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/notification_inspect_item" android:title="@string/status_bar_notification_inspect_item_title" /> -</menu> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 00715b275a8f..785894a92e59 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Skermkiekie geneem."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak om jou skermkiekie te sien."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Kon nie skermkiekie neem nie."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Kon nie skermkiekie stoor nie. Geheue kan dalk in gebruik wees."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB-lêeroordrag-opsies"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Heg as \'n mediaspeler (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Heg as \'n kamera (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gas"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ gas"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Laat gas uitgaan"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Een minuut lank"</item> <item quantity="other" msgid="6924190729213550991">"%d minute lank"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Maak batteryspaarder se instellings oop"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Laat gas uitgaan"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sal alles begin vasvang wat op jou skerm gewys word."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Moenie weer wys nie"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Begin nou"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index d6e482bb9ad1..4c9437fc786c 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"ቅጽበታዊ ገጽ እይታ ተቀርጿል"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"የአንተን ቅጽበታዊ ገጽ እይታ ለማየት ንካ"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"ቅጽበታዊ ገጽ እይታ መቅረጽ አልተቻለም::"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"የማያ ፎቶማስቀመጥ አልተቻለም። ማከማቻም አገልግሎት ላይ ሊሆን ይችላል።"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"የUSB ፋይል ሰደዳ አማራጮች"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"እንደ ማህደረ አጫዋች (MTP) ሰካ"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"እንደ ካሜራ (PTP) ሰካ"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string> <string name="guest_nickname" msgid="8059989128963789678">"እንግዳ"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ እንግዳ"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"እንግዳ ያስወጡ"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ለአንድ ደቂቃ"</item> <item quantity="other" msgid="6924190729213550991">"ለ%d ደቂቃዎች"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"የባትሪ ኃይል ቆጣቢ ቅንብሮች"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"ይዘቶች ተደብቀዋል"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"እንግዳ ያስወጡ"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በማያ ገጽዎ ላይ የታየውን ነገር በሙሉ ማንሳት ይጀምራል።"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"ዳግመኛ አታሳይ"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"አሁን ጀምር"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 91a1a060b562..ae9e3053a9f1 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"تم التقاط لقطة الشاشة."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"المس لعرض لقطة الشاشة."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"تعذر التقاط لقطة الشاشة."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"تعذر حفظ لقطة الشاشة. قد يكون التخزين قيد الاستخدام."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"خيارات نقل الملفات عبر USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"تحميل كمشغل وسائط (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"تحميل ككاميرا (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string> <string name="guest_nickname" msgid="8059989128963789678">"المدعو"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ مدعو"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"الخروج من وضع الضيف"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"لمدة دقيقة واحدة"</item> <item quantity="other" msgid="6924190729213550991">"لمدة %d من الدقائق"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"فتح إعدادات وضع توفير الطاقة"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"الخروج من وضع الضيف"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> سيبدأ التقاط كل شيء يتم عرضه على الشاشة."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"عدم الإظهار مرة أخرى"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"البدء الآن"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 32ace8ef67a4..a16629613ec7 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Екранната снимка е заснета."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Докоснете, за да видите екранната си снимка."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Екранната снимка не можа да бъде заснета."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Екранната снимка не можа да бъде запазена. Възможно е хранилището да се използва."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Опции за пренос на файлове чрез USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Свързване като медиен плейър (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Свързване като камера (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ гост"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Изход от сесията като гост"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"За една минута"</item> <item quantity="other" msgid="6924190729213550991">"За %d минути"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отваряне на настройките за режима за запазване на батерията"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Скрито съдържание"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Изход от сесията като гост"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ще започне да заснема всичко, което се показва на екрана ви."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Да не се показва отново"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Стартиране сега"</string> diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml index 0577ce259005..7bdc06abf3dd 100644 --- a/packages/SystemUI/res/values-bn-rBD/strings.xml +++ b/packages/SystemUI/res/values-bn-rBD/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"স্ক্রীনশট নেওয়া হযেছে৷"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"আপনার স্ক্রীনশট দেখতে স্পর্শ করুন৷"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"স্ক্রীনশট নেওয়া যায়নি৷"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"স্ক্রীনশট সংরক্ষণ করা যায়নি৷ সঞ্চয়স্থান ব্যবহারে থাকতে পারে৷"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ফাইল স্থানান্তরের বিকল্পগুলি"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"একটি মিডিয়া প্লেয়ার হিসাবে মাউন্ট করুন (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"একটি ক্যামেরা হিসাবে মাউন্ট করুন (PTP)"</string> @@ -254,7 +255,7 @@ <string name="zen_important_interruptions" msgid="3477041776609757628">"শুধুমাত্র প্রাধান্য বাধাগুলি"</string> <string name="zen_alarm_information_time" msgid="5235772206174372272">"আপনার পরবর্তী অ্যালার্মের সময় <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"আপনার পরবর্তী অ্যালার্মের সময় <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> - <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> বাজলে আপনার অ্যালার্ম শুনতে পাবেন না"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> বাজলে আপনি অ্যালার্ম শুনতে পাবেন না"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"নিচে অপেক্ষাকৃত কম জরুরী বিজ্ঞপ্তিগুলি"</string> <string name="notification_tap_again" msgid="7590196980943943842">"খোলার জন্য আবার আলতো চাপুন"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string> <string name="guest_nickname" msgid="8059989128963789678">"অতিথি"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ অতিথি"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"অতিথির প্রস্থান"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"এক মিনিটের জন্য"</item> <item quantity="other" msgid="6924190729213550991">"%d মিনিটের জন্য"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ব্যাটারি সেভার সেটিংস খুলুন"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"লুকানো বিষয়বস্তু"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"অতিথির প্রস্থান"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> আপনার স্ক্রীনে দেখানো সব কিছু ক্যাপচার করা শুরু করবে।"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"আর দেখাবেন না"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"এখন শুরু করুন"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index d651aaa0f30c..541d60d29a1c 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"S\'ha fet una captura de pantalla."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca per veure la captura de pantalla."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"No s\'ha pogut fer una captura de pantalla."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"No s\'ha pogut desar la captura de pantalla. És possible que l\'emmagatzematge estigui en ús."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opcions transf. fitxers USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Munta com a reproductor multimèdia (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Munta com a càmera (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Convidat"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidat"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Surt del mode de convidat"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durant un minut"</item> <item quantity="other" msgid="6924190729213550991">"Durant %d minuts"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Obre la configuració de la funció Estalvi de bateria"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Surt del mode de convidat"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> començarà a enregistrar tot el que es mostri a la pantalla."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"No ho tornis a mostrar"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Comença ara"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index c50e0e93f8c4..68b84a9a4f1e 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímek obrazovky zachycen."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Snímek obrazovky zobrazíte dotykem."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Snímek obrazovky se nepodařilo zachytit."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Snímek obrazovky se nepodařilo uložit. Je možné, že je externí úložiště právě používáno."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti přenosu souborů pomocí rozhraní USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Připojit jako přehrávač médií (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Připojit jako fotoaparát (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Host"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Přidat hosta"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Ukončit relaci hosta"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Na jednu minutu"</item> <item quantity="other" msgid="6924190729213550991">"Na %d min"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otevřít nastavení režimu Úspora baterie"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Ukončit relaci hosta"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávat vše, co je zobrazeno na obrazovce."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Tuto zprávu příště nezobrazovat"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Spustit"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index de110498a10f..f915332a0f02 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Skærmbilledet er gemt."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Tryk for at se dit skærmbillede."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Skærmbilledet kunne ikke tages."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Skærmbilledet kunne ikke gemmes. Eksternt lager kan være i brug."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Muligheder for USB-filoverførsel"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Isæt som en medieafspiller (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Isæt som et kamera (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gæst"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Gæst"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Forlad gæstesession"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"I ét minut"</item> <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Åbn indstillinger for Batteribesparende"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Indholdet er skjult"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Forlad gæstesession"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vil begynde at optage alt, hvad der vises på din skærm."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Start nu"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index a57d3a7d42d5..d7213ba25627 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot aufgenommen"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Zum Ansehen berühren"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot konnte nicht aufgenommen werden."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Screenshot konnte nicht gespeichert werden. Eventuell wird der Speicher gerade verwendet."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB-Dateiübertragungsoptionen"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Als Medienplayer (MTP) bereitstellen"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Als Kamera (PTP) bereitstellen"</string> @@ -168,11 +169,11 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Fenster schließen"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Mehr Zeit"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Weniger Zeit"</string> - <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G-Daten sind deaktiviert"</string> - <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-Daten sind deaktiviert"</string> - <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilfunkdaten sind deaktiviert"</string> - <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Daten sind deaktiviert"</string> - <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Die Daten wurden auf Ihrem Gerät deaktiviert, da das von Ihnen festgelegte Limit erreicht wurde.\n\nWenn Sie die Daten erneut aktivieren, berechnet Ihr Mobilfunkanbieter möglicherweise Gebühren."</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G-Daten deaktiviert"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-Daten deaktiviert"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilfunkdaten deaktiviert"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Daten deaktiviert"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Die Datennutzung wurde auf Ihrem Gerät deaktiviert, da das von Ihnen festgelegte Limit erreicht wurde.\n\nWenn Sie die Funktion erneut aktivieren, berechnet Ihr Mobilfunkanbieter möglicherweise Gebühren."</string> <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Daten aktivieren"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Gastmodus beenden"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Für eine Minute"</item> <item quantity="other" msgid="6924190729213550991">"Für %d Minuten"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Einstellungen für den Energiesparmodus öffnen"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Inhalte ausgeblendet"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Gastmodus beenden"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf Ihrem Bildschirm angezeigten Aktivitäten auf."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Jetzt starten"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index c913b72c54af..c972a69325cf 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Λήφθηκε το στιγμιότυπο οθόνης ."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Αγγίξτε για να δείτε το στιγμιότυπο οθόνης σας"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Αδύνατη η αποθήκευση του στιγμιότυπου οθόνης."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Αδύνατη η αποθήκευση στιγμιότυπου οθόνης. Ο εξωτερικός χώρος αποθήκευσης μπορεί να είναι σε χρήση."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Επιλογές μεταφοράς αρχείων μέσω USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Προσάρτηση ως μονάδας αναπαραγωγής μέσων (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Προσάρτηση ως κάμερας (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Επισκέπτης"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Επισκέπτης"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Έξοδος επισκέπτη"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Για ένα λεπτό"</item> <item quantity="other" msgid="6924190729213550991">"Για %d λεπτά"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Άνοιγμα ρυθμίσεων Εξοικονόμησης μπαταρίας"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Κρυφό περιεχόμενο"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Έξοδος επισκέπτη"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"Θα ξεκινήσει η καταγραφή του περιεχομένου που εμφανίζεται στην οθόνη σας από την εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Να μην εμφανιστεί ξανά"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Έναρξη τώρα"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index b0981b1c6ffa..e3fa73ff76f0 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Couldn\'t save screenshot. Storage may be in use."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string> @@ -223,7 +224,7 @@ <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string> <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string> - <string name="quick_settings_done" msgid="3402999958839153376">"Finished"</string> + <string name="quick_settings_done" msgid="3402999958839153376">"Done"</string> <string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string> <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string> <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Exit guest"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"For one minute"</item> <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Open battery saver settings"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Exit guest"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index b0981b1c6ffa..e3fa73ff76f0 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Couldn\'t save screenshot. Storage may be in use."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string> @@ -223,7 +224,7 @@ <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string> <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string> - <string name="quick_settings_done" msgid="3402999958839153376">"Finished"</string> + <string name="quick_settings_done" msgid="3402999958839153376">"Done"</string> <string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string> <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string> <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Exit guest"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"For one minute"</item> <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Open battery saver settings"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Exit guest"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index e69eec96026b..078eb86710af 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Se guardó la captura de pantalla."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver tu captura de pantalla."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"No se pudo guardar la captura de pantalla."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"No se pudo guardar la captura de pantalla. Puede que el almacenamiento esté en uso."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Activar como cámara (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Agregar invitado"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Salir de modo invitado"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item> <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configuración del ahorro de batería"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Salir de modo invitado"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comenzará la captura de todo lo que se muestre en la pantalla."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Comenzar ahora"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 48fe8de6993c..a4311b493b66 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura guardada"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver la captura de pantalla"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"No se ha podido guardar la captura de pantalla."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"No se ha podido guardar la captura de pantalla. Puede que el almacenamiento esté en uso."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Activar como cámara (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Añadir invitado"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Salir de modo invitado"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item> <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir ajustes de la función de ahorro de batería"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Salir de modo invitado"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> empezará a capturar todo lo que aparezca en la pantalla."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar ahora"</string> diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml index 10fdd0640c4c..01196bb6e5fb 100644 --- a/packages/SystemUI/res/values-et-rEE/strings.xml +++ b/packages/SystemUI/res/values-et-rEE/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekraanipilt on jäädvustatud."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Puudutage kuvatõmmise vaatamiseks."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvatõmmist ei saanud jäädvustada."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Kuvatõmmist ei saa salvestada. Mäluseade võib olla kasutuses."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB-failiedastuse valikud"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Paigalda meediumimängijana (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Paigalda kaamerana (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Külaline"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ külaline"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Välju külastaja režiimist"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Üheks minutiks"</item> <item quantity="other" msgid="6924190729213550991">"%d minutiks"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ava akusäästja seaded"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Sisu on peidetud"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Välju külastaja režiimist"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> hakkab jäädvustama kõike, mida ekraanil kuvatakse."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ära kuva uuesti"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Alusta kohe"</string> diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml index ddeadd9d1265..15a96e08640a 100644 --- a/packages/SystemUI/res/values-eu-rES/strings.xml +++ b/packages/SystemUI/res/values-eu-rES/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Pantaila-argazkia atera da."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Pantaila-argazkia ikusteko, ukitu ezazu."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Ezin izan da pantaila-argazkia atera."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Ezin izan da pantaila-argazkia gorde. Baliteke memoria erabiltzen aritzea."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB fitxategiak transferitzeko aukerak"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Muntatu multimedia-erreproduzigailu gisa (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Muntatu kamera gisa (PTP)"</string> @@ -191,7 +192,7 @@ <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetootha"</string> <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetootha (<xliff:g id="NUMBER">%d</xliff:g> gailu)"</string> <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetootha desaktibatuta"</string> - <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Ez dago bikotetutako gailurik erabilgarri"</string> + <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Ez dago parekatutako gailurik erabilgarri"</string> <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Distira"</string> <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Biratze automatikoa"</string> <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Biratzea blokeatuta"</string> @@ -213,8 +214,8 @@ <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ez dago sarerik"</string> <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi konexioa desaktibatuta"</string> <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Ez dago gordetako sarerik erabilgarri"</string> - <string name="quick_settings_cast_title" msgid="1893629685050355115">"Igorri pantaila"</string> - <string name="quick_settings_casting" msgid="6601710681033353316">"Igorpena"</string> + <string name="quick_settings_cast_title" msgid="1893629685050355115">"Igorri pantailako edukia"</string> + <string name="quick_settings_casting" msgid="6601710681033353316">"Igortzen"</string> <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Izenik gabeko gailua"</string> <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Igortzeko prest"</string> <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Ez dago gailurik erabilgarri"</string> @@ -236,7 +237,7 @@ <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Mugaren gainetik"</string> <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> erabilita"</string> <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Muga: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string> - <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> abisua"</string> + <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string> <string name="recents_empty_message" msgid="7883614615463619450">"Ez dago azkenaldian erabilitako aplikaziorik"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Aplikazioaren informazioa"</string> <string name="recents_lock_to_app_button_label" msgid="4793991421811647489">"aplikazio bakarreko modua"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gonbidatua"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Gonbidatua"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Irten gonbidatuen modutik"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Minutu batez"</item> <item quantity="other" msgid="6924190729213550991">"%d minutuz"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ireki bateria aurrezlearen ezarpenak"</string> <string name="battery_level_template" msgid="1609636980292580020">"%% <xliff:g id="LEVEL">%d</xliff:g>"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Edukiak ezkutatuta daude"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Irten gonbidatuen modutik"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak pantailan bistaratzen den guztia grabatuko du."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ez erakutsi berriro"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Hasi"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index c864170d5693..73a580089acc 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"تصویر صفحه گرفته شد."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"برای مشاهده تصویر صفحه خود، لمس کنید."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"تصویر صفحه گرفته نشد."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"تصویر صفحه ذخیره نشد. ممکن است دستگاه ذخیره در حال استفاده باشد."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"گزینههای انتقال فایل USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"نصب بهعنوان دستگاه پخش رسانه (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"تصب بهعنوان دوربین (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string> <string name="guest_nickname" msgid="8059989128963789678">"مهمان"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ مهمان"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"خروج مهمان"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"برای یک دقیقه"</item> <item quantity="other" msgid="6924190729213550991">"برای %d دقیقه"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"باز کردن تنظیمات ذخیره کننده باتری"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>٪٪"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"خروج مهمان"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع به ضبط هر چیزی میکند که در صفحهنمایش شما نمایش داده میشود."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"دوباره نشان داده نشود"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"اکنون شروع شود"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index e1d4661a105a..00431fae4642 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Kuvakaappaus tallennettu"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Katso kuvakaappaus koskettamalla."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvakaappausta ei voitu tallentaa"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Kuvakaappauksen tallennus epäonnistui. Ulkoinen tallennustila voi olla käytössä."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB-tiedostonsiirtoasetukset"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Käytä mediasoittimena (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Käytä kamerana (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Vieras"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Vieras"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Kirjaa vieras ulos"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Minuutiksi"</item> <item quantity="other" msgid="6924190729213550991">"%d minuutiksi"</item> @@ -283,7 +297,6 @@ <!-- no translation found for battery_level_template (1609636980292580020) --> <skip /> <string name="notification_hidden_text" msgid="1135169301897151909">"Sisältö piilotettu"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Kirjaa vieras ulos"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkaa tallentaa kaiken näytölläsi näkyvän."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Älä näytä uudelleen"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Aloita nyt"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index d92f0fb914b4..085d0b36a05c 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Impossible enregistrer capture d\'écran. Périphérique de stockage peut-être en cours d\'utilisation."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Installer comme un lecteur multimédia (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Installer comme un appareil photo (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Déconnecter l\'invité"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item> <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ouvrir les paramètres d\'économie d\'énergie"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Déconnecter l\'invité"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> commencer à enregistrer tout ce qui s\'affiche sur votre écran."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Commencer maintenant"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 61acdd587ea2..003168af566c 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Impossible enregistrer capture d\'écran. Périphérique de stockage peut-être en cours d\'utilisation."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Installer en tant que lecteur multimédia (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Installer en tant qu\'appareil photo (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Quitter le mode Invité"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item> <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ouvrir les paramètres de l\'économiseur de batterie"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Quitter le mode Invité"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va commencer à capturer tous les contenus affichés à l\'écran."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Commencer"</string> diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml index ca0df923b6cd..7e3b44166d9c 100644 --- a/packages/SystemUI/res/values-gl-rES/strings.xml +++ b/packages/SystemUI/res/values-gl-rES/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de pantalla gardada."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver a captura de pantalla."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Non se puido facer a captura de pantalla."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Non se puido gardar a captura de pantalla. É posible que o almacenamento estea en uso."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opcións de transferencia USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Inserir como reprodutor multimedia (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Inserir como cámara (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para finalizar a carga)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidado"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Retirar invitado"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item> <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir a configuración do aforrador de batería"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contido oculto"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Retirar invitado"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comezará a capturar todo o que apareza na túa pantalla."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrar outra vez"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar agora"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 86877c777b00..b1ac437e0241 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"स्क्रीनशॉट कैप्चर किया गया."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"अपना स्क्रीनशॉट देखने के लिए स्पर्श करें."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रीनशॉट को कैप्चर नहीं किया जा सका."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"स्क्रीनशॉट को सहेजा नहीं जा सका. संभवत: संग्रहण उपयोग में है."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB फ़ाइल स्थानांतरण विकल्प"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेयर के रूप में माउंट करें (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"कैमरे के रूप में माउंट करें (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूर्ण होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> शेष)"</string> <string name="guest_nickname" msgid="8059989128963789678">"अतिथि"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ अतिथि"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"अतिथि मोड से बाहर निकलें"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"एक मिनट के लिए"</item> <item quantity="other" msgid="6924190729213550991">"%d मिनट के लिए"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"बैटरी सेवर सेटिंग चालू करें"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"छिपी हुई सामग्री"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"अतिथि मोड से बाहर निकलें"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपके स्क्रीन पर प्रदर्शित प्रत्येक सामग्री को कैप्चर करना प्रारंभ कर देगी."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"फिर से न दिखाएं"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"अब प्रारंभ करें"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 1d586e1b445b..6e34b3509a70 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Zaslon je snimljen."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite za prikaz snimke zaslona."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Nije bilo moguće snimiti zaslon."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Nije bilo moguće spremiti snimku zaslona. Možda se upotrebljava pohrana."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prijenosa datoteka"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Učitaj kao media player (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Učitaj kao fotoaparat (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ gost"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Izlaz iz gostujućeg načina"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Jednu minutu"</item> <item quantity="other" msgid="6924190729213550991">"%d min"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otvaranje postavki štednje baterije"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je skriven"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Izlaz iz gostujućeg načina"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> počet će snimati sve što se prikazuje na zaslonu."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Započni sad"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index e9f6c291b448..f3e8025bdf37 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Képernyőkép rögzítve."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Megérintésével megtekintheti a képernyőképet."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Nem sikerült rögzíteni a képernyőképet."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Nem lehet menteni a képernyőképet. Lehet, hogy a tároló használatban van."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB-fájlátvitel beállításai"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Csatlakoztatás médialejátszóként (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Csatlakoztatás kameraként (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Vendég"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ vendég"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Vendég kiléptetése"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Egy percen át"</item> <item quantity="other" msgid="6924190729213550991">"%d percen át"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Akkumulátorkímélő mód beállításainak megnyitása"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>. szint"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalomjegyzék elrejtve"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Vendég kiléptetése"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazás rögzíteni fog mindent, ami megjelenik a képernyőn."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne jelenjen meg többé"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Indítás most"</string> diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index 0ff21369d5d3..813b253c8de0 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Էկրանի հանույթը լուսանկարվել է:"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Հպեք ձեր էկրանի հանույթը տեսնելու համար:"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Չհաջողվեց լուսանկարել էկրանի հանույթը:"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Չհաջողվեց պահել էկրանի հանույթը: Հնարավոր է` պահոցն օգտագործման մեջ է:"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ֆայլերի փոխանցման ընտրանքներ"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Միացնել որպես մեդիա նվագարկիչ (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Միացնել որպես ֆոտոխցիկ (PTP)"</string> @@ -166,18 +167,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Փակել վահանակը"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Ավելացնել ժամանակը"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Քչացնել ժամանակը"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G տվյալների կապն անջատված է"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G տվյալների կապն անջատված է"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Բջջային տվյալներն անջատված են"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Տվյալների կապն անջատված է"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Տվյալների կապը ձեր սարքում անջատվեց, քանի որ դուք հատել եք նշված սահմանաչափը:\n\nԱյն հետ միացնելուց հետո հնարավոր են հավելյալ վճարներ ձեր օպերատորից:"</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Միացնել տվյալների կապը"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Որոնում է GPS"</string> @@ -255,16 +250,12 @@ <string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string> <string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string> <string name="description_direction_left" msgid="7207478719805562165">"Սահեցրեք ձախ` <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Առանց ընդհատումների՝ ներառյալ զարթուցիչները"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"Առանց ընդհատումների"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"Միայն կարևոր ընդհատումներ"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"Ձեր հաջորդ զարթուցիչի ժամն է՝ <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Ձեր հաջորդ զարթուցիչի օրն է՝ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"Դուք չեք լսի ձեր զարթուցիչը <xliff:g id="ALARM_TIME">%s</xliff:g>-ին:"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"Պակաս հրատապ ծանուցումները ստորև"</string> <string name="notification_tap_again" msgid="7590196980943943842">"Կրկին հպեք՝ բացելու համար"</string> @@ -278,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Հյուր"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Հյուր"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Դուրս գալ հյուրի ռեժիմից"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Մեկ րոպե"</item> <item quantity="other" msgid="6924190729213550991">"%d րոպե"</item> @@ -291,12 +295,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Բացել մարտկոցի տնտեսման կարգավորումները"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Բովանդակությունը թաքցված է"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ծրագիրը կսկսի հավաքագրել այն ամենն ինչ ցուցադրվում է ձեր էկրանին:"</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"Այլևս ցույց չտալ"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"Մեկնարկել հիմա"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 8e39734727bc..80df5251a27b 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan layar diambil."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Sentuh untuk melihat tangkapan layar Anda."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat mengambil tangkapan layar."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Tidak dapat menyimpan tangkapan layar. Penyimpanan mungkin sedang digunakan."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opsi transfer file USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Pasang sebagai pemutar media (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Pasang sebagai kamera (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Tamu"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Tamu"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Keluar dari tamu"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Selama satu menit"</item> <item quantity="other" msgid="6924190729213550991">"Selama %d menit"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka setelan penghemat baterai"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Konten tersembunyi"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Keluar dari tamu"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mulai menangkap apa saja yang ditampilkan pada layar Anda."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tampilkan lagi"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Mulai sekarang"</string> diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml index 7378dff2bcf0..adae78d6cf59 100644 --- a/packages/SystemUI/res/values-is-rIS/strings.xml +++ b/packages/SystemUI/res/values-is-rIS/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Skjámynd var tekin."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Snertu til að skoða skjámyndina."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Ekki tókst að taka skjámynd."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Ekki tókst að vista skjámynd. Geymslan kann að vera í notkun."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Valkostir USB-skráaflutnings"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Tengja sem efnisspilara (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Tengja sem myndavél (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Í hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gestur"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Gestur"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Loka gestastillingu"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Í eina mínútu"</item> <item quantity="other" msgid="6924190729213550991">"Í %d mínútur"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Opna stillingar rafhlöðusparnaðar"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Innihald falið"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Loka gestastillingu"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mun fanga allt sem birtist á skjánum."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ekki sýna þetta aftur"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Byrja núna"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index f813cdff834c..8c8705695f93 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot acquisito."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Tocca per visualizzare il tuo screenshot."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Impossibile acquisire lo screenshot."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Impossibile salvare lo screenshot. L\'archivio esterno potrebbe essere in uso."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opzioni trasferimento file USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Monta come lettore multimediale (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Monta come videocamera (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Ospite"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ ospite"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Esci dalla modalità ospite"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Per un minuto"</item> <item quantity="other" msgid="6924190729213550991">"Per %d minuti"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Apri impostazioni risparmio batteria"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Esci dalla modalità ospite"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inizierà ad acquisire tutto ciò che è visualizzato sul tuo schermo."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Non·mostrare·più"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Avvia adesso"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index d0151bb7bafb..f5d67f39069d 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"צילום המסך בוצע."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"גע כדי להציג את צילום המסך שלך"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"לא ניתן לבצע צילום מסך."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"לא ניתן לשמור את צילום המסך. ייתכן שנעשה שימוש באמצעי אחסון."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"אפשרויות העברת קבצים ב-USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"טען כנגן מדיה (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"טען כמצלמה (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string> <string name="guest_nickname" msgid="8059989128963789678">"אורח"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ אורח"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"צא ממצב אורח"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"למשך דקה אחת"</item> <item quantity="other" msgid="6924190729213550991">"למשך %d דקות"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"פתח את ההגדרות של \'חיסכון בסוללה\'"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"התוכן מוסתר"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"צא ממצב אורח"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> יתחיל להקליט את כל התוכן המוצג במסך שלך."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"אל תציג שוב"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"התחל כעת"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 90d648d87bf1..060a5653e5f0 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"スクリーンショットを取得しました。"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"タップしてスクリーンショットを表示します。"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"スクリーンショットをキャプチャできませんでした。"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"スクリーンショットを保存できませんでした。ストレージが使用中の可能性があります。"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USBファイル転送オプション"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"メディアプレーヤー(MTP)としてマウント"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"カメラ(PTP)としてマウント"</string> @@ -253,7 +254,7 @@ <string name="description_direction_left" msgid="7207478719805562165">"左にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string> <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"サイレント(アラームなど)"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"サイレント"</string> - <string name="zen_important_interruptions" msgid="3477041776609757628">"優先的な中断のみ"</string> + <string name="zen_important_interruptions" msgid="3477041776609757628">"重要な通知のみ"</string> <string name="zen_alarm_information_time" msgid="5235772206174372272">"次のアラームは<xliff:g id="ALARM_TIME">%s</xliff:g>です"</string> <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"次のアラームは<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>です"</string> <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g>のアラームは鳴りません"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フル充電まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ ゲスト"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"ゲストを終了"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1分"</item> <item quantity="other" msgid="6924190729213550991">"%d分"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"バッテリーセーバーの設定を開く"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"コンテンツが非表示"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"ゲストを終了"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>で、画面に表示されているコンテンツのキャプチャを開始します。"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"次回から表示しない"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"今すぐ開始"</string> diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml index b9f24ecd99d9..a99730cbf626 100644 --- a/packages/SystemUI/res/values-ka-rGE/strings.xml +++ b/packages/SystemUI/res/values-ka-rGE/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"სკრინშოტი გადაღებულია."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"შეეხეთ ეკრანის სურათის სანახავად."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"ვერ მოხერხდა ეკრანის ანაბეჭდის გადაღება."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"ეკრანის სურათი ვერ შეინახა. შესაძლოა, მეხსიერება უკვე დაკავებულია."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ფაილის ტრანსფერის პარამეტრები"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"მედია-საკრავად (MTP) ჩართვა"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"მიუერთეთ როგორც კამერა (PTP)"</string> @@ -166,18 +167,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"არეს დახურვა"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"მეტი დრო"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"ნაკლები დრო"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G მონაც. გადაცემა გამორთულია"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G მონაც. გადაცემა გამორთულია"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ფიჭური ინტერნეტი გამორთულია"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"მონაცემთა გადაცემა გამორთულია"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"თქვენმა მოწყობილობამ მონაცემები გამორთო, რადგან თქვენ მიერ დაყენებულ ლიმიტს მიაღწია.\n\nმისი კვლავ გააქტიურებით შესაძლოა დაგეკისროთ გადასახადი თქვენი ოპერატორისგან."</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"მონაცემთა ჩართვა"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-ის ძებნა"</string> @@ -218,7 +213,7 @@ <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"არ არის დაკავშირებული."</string> <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ქსელი არ არის"</string> <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi გამორთულია"</string> - <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"შენახუი ქსელები მიუწვდომელია"</string> + <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"შენახული ქსელები მიუწვდომელია"</string> <string name="quick_settings_cast_title" msgid="1893629685050355115">"ეკრანის გადაცემა"</string> <string name="quick_settings_casting" msgid="6601710681033353316">"გადაიცემა"</string> <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"უსახელო მოწყობილობა"</string> @@ -255,16 +250,12 @@ <string name="description_target_search" msgid="3091587249776033139">"ძიება"</string> <string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string> <string name="description_direction_left" msgid="7207478719805562165">"გაასრიალეთ მარცხნივ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"შეწყვეტების გარეშე, მაღვიძარების ჩათვლით"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"შეწყვეტების გარეშე"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"მხოლოდ პრიორიტეტული შეწყვეტები"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"თქვენი შემდეგი მაღვიძარაა <xliff:g id="ALARM_TIME">%s</xliff:g>-ზე"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"თქვენი შემდეგი მაღვიძარაა <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"თქვენს მაღვიძარას <xliff:g id="ALARM_TIME">%s</xliff:g>-ზე ვერ გაიგონებთ"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"ქვემოთ მითითებულია ნაკლებად სასწრაფო შეტყობინებები"</string> <string name="notification_tap_again" msgid="7590196980943943842">"შეეხეთ ისევ გასახსნელად"</string> @@ -278,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string> <string name="guest_nickname" msgid="8059989128963789678">"სტუმარი"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ სტუმარი"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"სტუმრის გასვლა"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ერთი წუთით"</item> <item quantity="other" msgid="6924190729213550991">"%d წუთით"</item> @@ -291,12 +295,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ბატარეის დამზოგის პარამეტრების გახსნა"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"შიგთავსი დამალულია"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> დაიწყებს იმ ყველაფრის აღბეჭდვას, რაც თქვენს ეკრანზე ჩანს."</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"აღარ მაჩვენო"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"დაწყება ახლავე"</string> </resources> diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml index a3505a3b8f7f..de114d2c9db4 100644 --- a/packages/SystemUI/res/values-kk-rKZ/strings.xml +++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сақталды."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Скриншотты көру үшін түрту."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот жасалмады."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Скриншотты сақтай алмады. Жад қолданыста болуы мүмкін."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB файлын жіберу опциялары"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойнатқыш (MTP) ретінде қосыңыз"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Камера ретінде (PTP) қосыңыз"</string> @@ -166,18 +167,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Тақтаны жабу"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Көбірек уақыт"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Азырақ уақыт"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G деректері өшірулі"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G деректері өшірулі"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Ұялы деректер өшірулі"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Деректер өшірулі"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Құрылғыңыз сіз орнатқан шекке жеткендіктен деректерді өшірді.\n\nОны қайтадан қосу оператордың ақылар алуына әкелуі мүмкін."</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Деректерді қосу"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS қызметін іздеуде"</string> @@ -255,16 +250,12 @@ <string name="description_target_search" msgid="3091587249776033139">"Іздеу"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үшін жоғары сырғыту."</string> <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үшін солға сырғыту."</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Үзілістерсіз, соның ішінде, дабылдарсыз"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"Үзулерсіз"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"Тек басым үзулер"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"Келесі дабыл — <xliff:g id="ALARM_TIME">%s</xliff:g> уақытында"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Келесі дабыл — <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> уақытында дабылды естімейсіз"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"Шұғылдығы азырақ хабарландырулар төменде"</string> <string name="notification_tap_again" msgid="7590196980943943842">"Ашу үшін қайта түртіңіз"</string> @@ -278,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Қонақ"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Қонақ"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Қонақтан шығу"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Бір минут бойы"</item> <item quantity="other" msgid="6924190729213550991">"%d минут бойы"</item> @@ -291,12 +295,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Батарея үнемдегіш параметрлерін ашу"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмұн жасырылған"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранда көрсетілгеннің барлығын түсіре бастайды."</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"Қайта көрсетпеу"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"Қазір бастау"</string> </resources> diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index 6b2d46d02b15..0ac6f40ae29f 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"បានចាប់យករូបថតអេក្រង់។"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"ប៉ះ ដើម្បីមើលរូបថតអេក្រង់របស់អ្នក។"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"មិនអាចចាប់យករូបថតអេក្រង់។"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"មិនអាចរក្សាទុករូបថតអេក្រង់។ ឧបករណ៍ផ្ទុកអាចកំពុងប្រើ។"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"ជម្រើសផ្ទេរឯកសារតាមយូអេសប៊ី"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"ភ្ជាប់ជាកម្មវិធីចាក់មេឌៀ (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"ភ្ជាប់ជាម៉ាស៊ីនថត (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុងបញ្ចូលថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string> <string name="guest_nickname" msgid="8059989128963789678">"ភ្ញៀវ"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ ភ្ញៀវ"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"ភ្ញៀវចាកចេញ"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"សម្រាប់មួយនាទី"</item> <item quantity="other" msgid="6924190729213550991">"សម្រាប់ %d នាទី"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"បើកការកំណត់កម្មវិធីសន្សំថ្ម"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"បានលាក់មាតិកា"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"ភ្ញៀវចាកចេញ"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹងចាប់ផ្ដើមចាប់យកអ្វីៗគ្រប់យ៉ាងដែលបង្ហាញលើអេក្រង់របស់អ្នក។"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"កុំបង្ហាញម្ដងទៀត"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"ចាប់ផ្ដើមឥឡូវ"</string> diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml index 2c58be60256f..d89687ecaa7f 100644 --- a/packages/SystemUI/res/values-kn-rIN/strings.xml +++ b/packages/SystemUI/res/values-kn-rIN/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ಶಾಟ್ ವೀಕ್ಷಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಸೆರೆಹಿಡಿಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ಸಂಗ್ರಹಣೆಯು ಬಳಕೆಯಲ್ಲಿರಬಹುದು."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ಫೈಲ್ ವರ್ಗಾವಣೆ ಆಯ್ಕೆಗಳು"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"ಮೀಡಿಯಾ ಪ್ಲೇಯರ್ ರೂಪದಲ್ಲಿ ಅಳವಡಿಸಿ (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"ಕ್ಯಾಮರಾ ರೂಪದಲ್ಲಿ ಅಳವಡಿಸಿ (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ ( ಪೂರ್ತಿ ಆಗುವವರೆಗೆ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"ಅತಿಥಿ"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ ಅತಿಥಿ"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"ಅತಿಥಿ ಅನ್ನು ನಿರ್ಗಮಿಸಿ"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ಒಂದು ನಿಮಿಷದವರೆಗೆ"</item> <item quantity="other" msgid="6924190729213550991">"%d ನಿಮಿಷಗಳವರೆಗೆ"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ಬ್ಯಾಟರಿ ರಕ್ಷಕದ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"ವಿಷಯಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"ಅತಿಥಿ ಅನ್ನು ನಿರ್ಗಮಿಸಿ"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"ನಿಮ್ಮ ಪರದೆಯ ಮೇಲೆ ಪ್ರದರ್ಶಿಸಲಾಗುವ ಎಲ್ಲವನ್ನೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಯು ಸೆರೆಹಿಡಿಯಲು ಪ್ರಾರಂಭಿಸುತ್ತದೆ."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸದಿರಿ"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"ಈಗ ಪ್ರಾರಂಭಿಸಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 4e05e9c4bebc..f2488f696ed6 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -75,7 +75,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"캡쳐화면 저장됨"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"캡쳐화면을 보려면 터치하세요."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"캡쳐화면을 캡쳐하지 못했습니다."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"캡쳐화면을 저장할 수 없습니다. 저장소를 사용 중인 것 같습니다."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB 파일 전송 옵션"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"미디어 플레이어로 마운트(MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"카메라로 마운트(PTP)"</string> @@ -172,7 +173,7 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G 데이터 사용 중지됨"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"이동통신 데이터 사용 중지됨"</string> <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"데이터 사용 중지됨"</string> - <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"기기가 설정 한도에 도달하여 데이터를 사용 중지했습니다.\n\n데이터를 다시 사용 설정하면 이동통신사로부터 대금이 청구될 수 있습니다."</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"데이터가 설정 한도에 도달하여 사용 중지되었습니다.\n\n데이터를 다시 사용 설정하면 이동통신사로부터 대금이 청구될 수 있습니다."</string> <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"데이터 사용 설정"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string> <string name="guest_nickname" msgid="8059989128963789678">"손님"</string> <string name="guest_new_guest" msgid="4259024453643879653">"새 손님 추가"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"손님 모드 종료"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1분 동안"</item> <item quantity="other" msgid="6924190729213550991">"%d분 동안"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"배터리 세이버 설정 열기"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"숨겨진 콘텐츠"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"손님 모드 종료"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 화면에 표시된 모든 것을 캡처하기 시작합니다."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"다시 표시 안함"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"시작하기"</string> diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml index 9f6892ccde2e..0d6867c919d6 100644 --- a/packages/SystemUI/res/values-ky-rKG/strings.xml +++ b/packages/SystemUI/res/values-ky-rKG/strings.xml @@ -96,7 +96,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот тартылды."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Тийип, скриншотту көрүңүз."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот кылынбай жатат."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Скриншот сакталбай жатат. Сактагыч пайдаланууда болушу мүмкүн."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <!-- no translation found for usb_preference_title (6551050377388882787) --> <skip /> <!-- no translation found for use_mtp_button_title (4333504413563023626) --> @@ -192,18 +193,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Тактаны жабуу"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Көбүрөөк убакыт"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Азыраак убакыт"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2Гб-3Гб көлөмдөгү дайындар өчүрүлдү."</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4Гб көлөмдөгү дайындар өчүрүлдү"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Уюктук дайындар тармагы өчүк"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дайындарды кабыл алуу өчүрүлгөн."</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Белгиленген эң жогорку чекке жеткендиктен, түзмөгүңүз дайындарды кабыл алууну токтотту.\n\nДайындарды кабыл алууну улантам десеңиз, операторго акы төлөп калышыңыз мүмкүн."</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Дайындарды алууну иштетүү"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS издөө"</string> @@ -281,16 +276,12 @@ <string name="description_target_search" msgid="3091587249776033139">"Издөө"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үчүн жогору жылмыштырыңыз."</string> <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үчүн солго жылмыштырыңыз."</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Үзгүлтүктөр, ошондой эле үн ишараттары болбойт"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"Үзгүлтүксүз"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"Артыкчылыктуу үзгүлтүктөр гана"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"Кийинки үн ишараты саат <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Кийинки үн ишараты <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"Саат <xliff:g id="ALARM_TIME">%s</xliff:g> үн ишаратын укпайсыз."</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"Анчейин шашылыш эмес эскертмелер төмөндө"</string> <string name="notification_tap_again" msgid="7590196980943943842">"Ачуу үчүн кайра таптап коюңуз"</string> @@ -304,6 +295,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Кубатталууда (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> толгонго чейин)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Конок"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Конок"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Конок режиминен чыгуу"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Бир мүнөткө"</item> <item quantity="other" msgid="6924190729213550991">"%d мүнөткө"</item> @@ -317,12 +321,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Батареяны үнөмдөгүчтүн жөндөөлөрүн ачуу"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранга чыккан нерсенин баарын сүрөткө тарта баштайт."</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"Экинчи көрсөтүлбөсүн"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"Азыр баштоо"</string> </resources> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index ef98cca9aa33..83ace48a4c93 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"ຖ່າຍຮູບໜ້າຈໍແລ້ວ"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"ແຕະເພື່ອເບິ່ງພາບໜ້າຈໍຂອງທ່ານ."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"ບໍ່ສາມາດບັນທຶກພາບໜ້າຈໍໄດ້. ບ່ອນຈັດເກັບອາດກຳລັງຖືກນຳໃຊ້ຢູ່."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ໂຕເລືອກການຍ້າຍໄຟລ໌"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"ເຊື່ອມຕໍ່ເປັນ media player (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"ເຊື່ອມຕໍ່ເປັນກ້ອງຖ່າຍຮູບ (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳລັງສາກໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າຈະເຕັມ)"</string> <string name="guest_nickname" msgid="8059989128963789678">"ແຂກ"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ ແຂກ"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"ອອກຈາກຜູ່ມາຢາມ"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ເປັນເວລານຶ່ງນາທີ"</item> <item quantity="other" msgid="6924190729213550991">"ເປັນເວລາ %d ນາທີ"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ເປີດການຕັ້ງຄ່າໂຕປະຢັດແບັດເຕີຣີ"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"ເນື້ອຫາຖືກເຊື່ອງແລ້ວ"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"ອອກຈາກຜູ່ມາຢາມ"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ຈະເລີ່ມບັນທຶກທຸກຢ່າງທີ່ສະແດງຜົນໃນໜ້າຈໍທ່ານ."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"ບໍ່ຕ້ອງສະແດງອີກ"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"ເລີ່ມດຽວນີ້"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index bdbcf6480ff8..567aa0092b8a 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrano kopija užfiksuota."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Palieskite, kad peržiūrėtumėte ekrano kopiją."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Nepavyko užfiksuoti ekrano kopijos."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Nepavyko išsaugoti ekrano kopijos. Gali būti naudojama atmintis."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB failo perdavimo parinktys"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos leistuvę (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Įmontuoti kaip fotoaparatą (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Svečias"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Svečias"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Išeiti iš svečio režimo"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 min."</item> <item quantity="other" msgid="6924190729213550991">"%d min."</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Atidaryti akumuliatoriaus tausojimo priemonės nustatymus"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Turinys paslėptas"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Išeiti iš svečio režimo"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"„<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ pradės fiksuoti viską, kas rodoma jūsų ekrane."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Daugiau neberodyti"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Pradėti dabar"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index cf3996a37440..3eb35aa3dce8 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrānuzņēmums ir uzņemts."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Pieskarieties, lai skatītu ekrānuzņēmumu."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Nevarēja uzņemt ekrānuzņēmumu."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Nevarēja saglabāt ekrānuzņēmumu. Iespējams, tiek izmantota atmiņa."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB failu pārsūtīšanas opcijas"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Pievienot kā multivides atskaņotāju (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Pievienot kā kameru (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Viesis"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+Viesis"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Iziet no viesa režīma"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Vienu minūti"</item> <item quantity="other" msgid="6924190729213550991">"%d min"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Atvērt akumulatora enerģijas taupīšanas režīma iestatījumus"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Saturs paslēpts"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Iziet no viesa režīma"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sāks uzņemt visu, kas tiks rādīts jūsu ekrānā."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Vairs nerādīt"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Sākt tūlīt"</string> diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml index 803e02887213..39021cad90d0 100644 --- a/packages/SystemUI/res/values-mk-rMK/strings.xml +++ b/packages/SystemUI/res/values-mk-rMK/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Сликата на екранот е снимена."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Допрете за да ја видите сликата на екранот."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Сликата на екранот не можеше да се сними."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Сликата на екранот не можеше да се зачува. Можеби меморијата е во употреба."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Пренос на датотека со УСБ"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Монтирај како мултимедијален плеер (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Монтирај како фотоапарат (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Се полни (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Гостин"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ гостин"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Излези како гостин"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"За една минута"</item> <item quantity="other" msgid="6924190729213550991">"За %d минути"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отвори ги поставките за штедачот на батерија"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Содржините се скриени"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Излези како гостин"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе започне да презема сѐ што се прикажува на вашиот екран."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Не покажувај повторно"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Започни сега"</string> diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml index 663aa355364b..61f949b4320c 100644 --- a/packages/SystemUI/res/values-ml-rIN/strings.xml +++ b/packages/SystemUI/res/values-ml-rIN/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"സ്ക്രീൻഷോട്ട് എടുത്തു."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"നിങ്ങളുടെ സ്ക്രീൻഷോട്ട് കാണാനായി സ്പർശിക്കുക."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കാൻ കഴിഞ്ഞില്ല. സംഭരണം ഉപയോഗത്തിലായിരിക്കാം."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ഫയൽ കൈമാറൽ ഓപ്ഷനുകൾ"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"ഒരു മീഡിയ പ്ലേയറായി (MTP) മൗണ്ടുചെയ്യുക"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"ഒരു ക്യാമറയായി (PTP) മൗണ്ടുചെയ്യുക"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ചാർജ്ജുചെയ്യുന്നു (പൂർണ്ണമാകുന്നതിന്, <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"അതിഥി"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ അതിഥി"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ഒരു മിനിറ്റ് ദൈർഘ്യം"</item> <item quantity="other" msgid="6924190729213550991">"%d മിനിറ്റ് ദൈർഘ്യം"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ബാറ്ററി സേവർ ക്രമീകരണങ്ങൾ തുറക്കുക"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"കോൺടാക്റ്റുകൾ മറച്ചു"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"നിങ്ങളുടെ സ്ക്രീനിൽ പ്രദർശിപ്പിച്ചിരിക്കുന്ന എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ക്യാപ്ചർ ചെയ്യുന്നത് ആരംഭിക്കും."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"വീണ്ടും കാണിക്കരുത്"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"ഇപ്പോൾ ആരംഭിക്കുക"</string> diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml index e4d3222ab3b2..2149df3e2cc4 100644 --- a/packages/SystemUI/res/values-mn-rMN/strings.xml +++ b/packages/SystemUI/res/values-mn-rMN/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Дэлгэцийн агшинг авсан."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Дэлгэцийн агшныг харах бол хүрнэ үү."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Дэлгэцийн агшинг авч чадсангүй."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Дэлгэцийн агшинг хадгалж чадсангүй. Сан ашиглагдаж байгаа бололтой."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB файл шилжүүлэх сонголт"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа тоглуулагч(MTP) болгон залгах"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Камер болгон(PTP) залгах"</string> @@ -268,6 +269,13 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Зочин"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Зочин"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Зочноос гарах"</string> + <string name="guest_exit_guest_dialog_title" msgid="7587460301980067285">"Зочны нэвтрэлтээс гарч байна уу?"</string> + <string name="guest_exit_guest_dialog_message" msgid="10255285459589280">"Зочны нэвтрэлтээс гарснаар локал датаг арилгах болно."</string> + <string name="guest_wipe_session_title" msgid="6419439912885956132">"Тавтай морилно уу!"</string> + <string name="guest_wipe_session_message" msgid="5369763062345463297">"Та шинээр нэвтрэх гэж байна уу?"</string> + <string name="guest_wipe_session_wipe" msgid="9154291314115781448">"Тийм"</string> + <string name="guest_wipe_session_dontwipe" msgid="850084868661344050">"Үгүй, баярлалаа"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Нэг минутын турш"</item> <item quantity="other" msgid="6924190729213550991">"%d минутын турш"</item> @@ -281,7 +289,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Батерей хэмнэгчийн тохиргоог нээх"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Контентыг нуусан"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Зочноос гарах"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> таны дэлгэц дээр гаргасан бүх зүйлийн зургийг авч эхэлнэ."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Дахиж үл харуулах"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Одоо эхлүүлэх"</string> diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml index 36e2caa19790..4e6914d41433 100644 --- a/packages/SystemUI/res/values-mr-rIN/strings.xml +++ b/packages/SystemUI/res/values-mr-rIN/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"स्क्रीनशॉट कॅप्चर केला."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"आपला स्क्रीनशॉट पाहण्यासाठी स्पर्श करा."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रीनशॉट कॅप्चर करू शकलो नाही."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"स्क्रीनशॉट जतन करू शकलो नाही. संचयन वापरात असू शकते."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB फाईल स्थानांतरण पर्याय"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेअर म्हणून माउंट करा (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"कॅमेरा म्हणून माउंट करा (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) चार्ज होत आहे"</string> <string name="guest_nickname" msgid="8059989128963789678">"अतिथी"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ अतिथी"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"निर्गमन करणारे अतिथी"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"एक मिनिटासाठी"</item> <item quantity="other" msgid="6924190729213550991">"%d मिनिटांसाठी"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"बॅटरी बचतकर्ता सेटिंग्ज उघडा"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"लपविलेली सामग्री"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"निर्गमन करणारे अतिथी"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपल्या स्क्रीनवर प्रदर्शित होणारी प्रत्येक गोष्ट कॅप्चर करणे प्रारंभ करेल."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"पुन्हा दर्शवू नका"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"आता प्रारंभ करा"</string> diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml index 543f0f98e53b..3e5e3c33e1fa 100644 --- a/packages/SystemUI/res/values-ms-rMY/strings.xml +++ b/packages/SystemUI/res/values-ms-rMY/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan skrin ditangkap."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Sentuh untuk melihat tangkapan skrin anda."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat menangkap tangkapan skrin."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Tidak boleh menyimpan tangkapan skrin. Storan mungkin sedang digunakan."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Pilihan pemindahan fail USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Lekapkan sebagai pemain media (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Lekapkan sebagai kamera (PTP)"</string> @@ -166,18 +167,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Tutup panel"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Lagi masa"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Kurang masa"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data 2G-3G dimatikan"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data 4G dimatikan"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data selular dimatikan"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data dimatikan"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Peranti anda mematikan data kerana telah mencapai had yang anda tetapkan.\n\nMenghidupkan data semula boleh menyebabkan anda dikenakan caj oleh pembawa anda."</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Hidupkan data"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Mencari GPS"</string> @@ -220,7 +215,7 @@ <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Dimatikan"</string> <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Tiada rangkaian disimpan tersedia"</string> <string name="quick_settings_cast_title" msgid="1893629685050355115">"Skrin Cast"</string> - <string name="quick_settings_casting" msgid="6601710681033353316">"Barisan Pelakon"</string> + <string name="quick_settings_casting" msgid="6601710681033353316">"Menghantar"</string> <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Peranti tidak bernama"</string> <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Bersedia untuk menghantar"</string> <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Tiada peranti tersedia"</string> @@ -242,7 +237,7 @@ <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Melebihi had"</string> <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> digunakan"</string> <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> had"</string> - <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> amaran"</string> + <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string> <string name="recents_empty_message" msgid="7883614615463619450">"Tiada apl terbaharu"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string> <string name="recents_lock_to_app_button_label" msgid="4793991421811647489">"kunci ke apl"</string> @@ -255,16 +250,12 @@ <string name="description_target_search" msgid="3091587249776033139">"Carian"</string> <string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> <string name="description_direction_left" msgid="7207478719805562165">"Luncurkan ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Tiada gangguan, termasuk penggera"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"Tiada gangguan"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"Gangguan keutamaan sahaja"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"Penggera anda yang seterusnya pada <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Penggera anda yang seterusnya pada <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"Anda tdk akan mdgr penggera anda pd <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"Pemberitahuan kurang penting di bawah"</string> <string name="notification_tap_again" msgid="7590196980943943842">"Ketik lagi untuk membuka"</string> @@ -278,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Tetamu"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Tetamu"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Tetamu keluar"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Selama satu minit"</item> <item quantity="other" msgid="6924190729213550991">"Selama %d minit"</item> @@ -291,12 +295,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka tetapan penjimat bateri"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Kandungan tersembunyi"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mula mengabadikan semua yang dipaparkan pada skrin anda.."</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tunjukkan lagi"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"Mulakan sekarang"</string> </resources> diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml index 9f06442deeb4..7176c3418f71 100644 --- a/packages/SystemUI/res/values-my-rMM/strings.xml +++ b/packages/SystemUI/res/values-my-rMM/strings.xml @@ -71,7 +71,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား ဖမ်းယူပြီး"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"သင့်ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား ကြည့်ရှုရန် ထိပါ"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား မဖမ်းစီးနိုင်ပါ"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား မသိမ်းဆည်းနိုင်ပါ သိမ်းဆည်းမှုအား အသုံးပြုနေပါလိမ့်မည်"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ဖိုင်ပြောင်း ရွေးမှုများ"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"မီဒီယာပလေရာအနေဖြင့် တပ်ဆင်ရန် (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"ကင်မရာအနေဖြင့် တပ်ဆင်ရန် (PTP)"</string> @@ -266,6 +267,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> အပြည့် အထိ) အားသွင်းနေ"</string> <string name="guest_nickname" msgid="8059989128963789678">"ဧည့်သည်"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ ဧည့်သည်"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"ဧည့်သည့် ထွက်ရန်"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"တစ်မိနစ် အတွင်း"</item> <item quantity="other" msgid="6924190729213550991">"%d မိနစ် အတွင်း"</item> @@ -277,7 +291,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ဘက်ထရီ ချွေတာသူ ဆက်တင်များကို ဖွင့်ရန်"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"အကြောင်းအရာများ ဝှက်ထား"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"ဧည့်သည့် ထွက်ရန်"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> က သင်၏ မျက်နှာပြင် ပေါ်မှာ ပြသထားသည့် အရာတိုင်းကို စတင် ဖမ်းယူမည်။"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"နောက်ထပ် မပြပါနှင့်"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"ယခု စတင်ပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 587e11912aee..f3d78bc7ac4a 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Skjermdumpen er lagret."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Trykk for å se skjermdumpen."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Kan ikke lagre skjermdumpen."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Kan ikke ikke lagre skjermdumpen. Det er mulig ekstern lagring er i bruk."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Altern. for USB-filoverføring"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Sett inn som mediespiller (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Sett inn som kamera (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gjest"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Gjest"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Avslutt gjesteøkten"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"I ett minutt"</item> <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Åpen innstilling for batterisparing"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Innholdet er skjult"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Avslutt gjesteøkten"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar opp alt som vies på skjermen din."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ikke vis igjen"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Start nå"</string> diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml index baefb8107ed0..d1631ff9f08e 100644 --- a/packages/SystemUI/res/values-ne-rNP/strings.xml +++ b/packages/SystemUI/res/values-ne-rNP/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"स्क्रिनसट क्याप्चर गरियो।"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"तपाईँको स्क्रिनसट हेर्न छुनुहोस्।"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रिनसट क्याप्चर गर्न सकिएन।"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"स्क्रिनसटलाई बचत गर्न सकेन। भण्डारण उपयोगमा हुन सक्छ।"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB फाइल सार्ने विकल्पहरू"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"मिडिया प्लेयर(MTP)को रूपमा माउन्ट गर्नुहोस्"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"क्यामेराको रूपमा माउन्ट गर्नुहोस् (PTP)"</string> @@ -169,7 +170,7 @@ <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G डेटा बन्द छ"</string> <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G डेटा बन्द छ"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"सेलुलर डेटा बन्द छ"</string> - <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"तथ्याङ्क बन्द छ"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"डेटा बन्द छ"</string> <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"तपाईंले सेट गर्नु भएको सीमा पुगेको हुनाले तपाईंको उपकरणले डेटा बंद गर्यो।\n\n यसलाई फिर्ता गर्दा आफ्नो वाहक बाट शुल्क लिन सक्छ।"</string> <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"डेटा खोल्नुहोस्"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण भएसम्म)"</string> <string name="guest_nickname" msgid="8059989128963789678">"अतिथि"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+अतिथि"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"अतिथि बन्द"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"एक मिनेटको लागि"</item> <item quantity="other" msgid="6924190729213550991">"%d मिनेटको लागि"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ब्याट्री सेभर सेटिङ्हरू खुला गर्नुहोस्"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"लुकेका सामाग्रीहरू"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"निकास अतिथि"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले आफ्नो स्क्रीनमा प्रदर्शित हुने सबै खिच्न शुरू गर्नेछ।"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"फेरि नदेखाउनुहोस्"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"अहिले सुरु गर्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 11222243b453..54e590f97bef 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot gemaakt."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om uw screenshot te bekijken."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot is niet gemaakt."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Kan screenshot niet opslaan. Mogelijk is de opslag in gebruik."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opties voor USB-bestandsoverdracht"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Koppelen als mediaspeler (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Koppelen als camera (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Gastmodus verlaten"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Eén minuut"</item> <item quantity="other" msgid="6924190729213550991">"%d minuten"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Instellingen voor Accubesparing openen"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Gastmodus verlaten"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> gaat alles vastleggen dat wordt weergegeven op uw scherm."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Niet opnieuw weergeven"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Nu starten"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index bfa9b124c3e9..907f8616f337 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Wykonano zrzut ekranu."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Dotknij, aby wyświetlić zrzut ekranu."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Nie udało się wykonać zrzutu ekranu."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Nie udało się zapisać zrzutu ekranu. Pamięć może być w użyciu."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB – opcje przesyłania plików"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Podłącz jako odtwarzacz multimedialny (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Podłącz jako aparat (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gość"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Dodaj gościa"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Zakończ tryb gościa"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Przez minutę"</item> <item quantity="other" msgid="6924190729213550991">"Przez %d min"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otwórz ustawienia oszczędzania baterii"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Treści ukryte"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Zakończ tryb gościa"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie zapisywać wszystko, co wyświetli się na ekranie."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Nie pokazuj ponownie"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Rozpocznij teraz"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 65d737ab1bbc..b25c1a33578b 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de ecrã efetuada"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para ver a captura de ecrã"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter captura de ecrã."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Não foi possível guardar a captura de ecrã. O armazenamento poderá estar a ser utilizado."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opções de transm. de fich. USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Montar como leitor de multimédia (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como câmara (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidado"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Sair de modo convidado"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durante um minuto"</item> <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir as definições de poupança de bateria"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Sair de modo convidado"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"O(a) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vai começar a captar tudo o que é apresentado no ecrã."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar de novo"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Começar agora"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index a6df53121121..fc0d95a9791a 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de tela obtida."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para visualizar a captura de tela."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter a captura de tela."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Não foi possível salvar a captura de tela. O armazenamento pode estar em uso."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opções transf. arq. por USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Conectar como media player (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como uma câmera (PTP)"</string> @@ -168,18 +169,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Fechar painel"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Mais tempo"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Menos tempo"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Os dados 2G-3G foram desativados"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Os dados 4G foram desativados"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Os dados da rede celular foram desativados"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Os dados foram desativados"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"O dispositivo desativou os dados porque o limite definido foi atingido.\n\nAtivá-los novamente poderá resultar em cobranças de sua operadora."</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ativar dados"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string> @@ -257,16 +252,12 @@ <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para cima."</string> <string name="description_direction_left" msgid="7207478719805562165">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para a esquerda."</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Sem interrupções, incluindo alarmes"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"Sem interrupções"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"Apenas interrupções prioritárias"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"Seu próximo alarme será às <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Seu próximo alarme será em <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"Você não ouvirá o alarme às <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificações menos urgentes abaixo"</string> <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string> @@ -280,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ convidado"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Remover convidado"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Por 1 minuto"</item> <item quantity="other" msgid="6924190729213550991">"Por %d minutos"</item> @@ -293,12 +297,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configurações de economia de bateria"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar agora"</string> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 19dadc4a343b..08c0691898ea 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Captură de ecran realizată."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Atingeţi pentru a vedea captura de ecran."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Captura de ecran nu a putut fi realizată."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Captura de ecran nu a putut fi salvată. Este posibil să fie utilizată stocarea."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opţiuni pentru transferul de fişiere prin USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Montaţi ca player media (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Montaţi drept cameră foto (PTP)"</string> @@ -213,10 +214,10 @@ <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nicio reţea"</string> <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi deconectat"</string> <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nicio rețea salvată disponibilă"</string> - <string name="quick_settings_cast_title" msgid="1893629685050355115">"Trimiteți ecranul"</string> - <string name="quick_settings_casting" msgid="6601710681033353316">"Se trimite"</string> + <string name="quick_settings_cast_title" msgid="1893629685050355115">"Proiectați ecranul"</string> + <string name="quick_settings_casting" msgid="6601710681033353316">"Se proiectează"</string> <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispozitiv nedenumit"</string> - <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pregătit pentru a trimite"</string> + <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pregătit pentru proiecție"</string> <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Niciun dispozitiv disponibil"</string> <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string> <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Invitat"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Invitat"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Închideți invitatul"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Timp de un minut"</item> <item quantity="other" msgid="6924190729213550991">"Timp de %d (de) minute"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Deschideți setările pentru economisirea bateriei"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Conținutul este ascuns"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Închideți invitatul"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va începe să captureze tot ceea ce se afișează pe ecran."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Nu se mai afișează"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Începeți acum"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 8bbfd04daa99..924c63ed9b2a 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сохранен"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Нажмите, чтобы просмотреть"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Не удалось сохранить скриншот."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Не удалось сохранить скриншот. Возможно, накопители заняты."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Параметры передачи через USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Подключить как мультимедийный проигрыватель (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Установить как камеру (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Гость"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Добавить гостя"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Выйти из гостевого режима"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 мин."</item> <item quantity="other" msgid="6924190729213550991">"%d мин."</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Открыть настройки режима энергосбережения"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Содержимое скрыто"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Выйти из гостевого режима"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"Приложение <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> получит доступ к изображению на экране устройства."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Больше не показывать"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Начать"</string> diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml index 7c5c702de0e2..929ab5d5d2fc 100644 --- a/packages/SystemUI/res/values-si-rLK/strings.xml +++ b/packages/SystemUI/res/values-si-rLK/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"තිර රුව ග්රහණය කරන ලදි."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"ඔබගේ තිර රුව බැලීමට ස්පර්ශ කරන්න."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"තිර රුව ග්රහණය කිරීමට නොහැකි විය."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"තිර රුව සුරැකීමට නොහැකි විය. ආචයනය භාවිතාවේ තිබෙනවා විය හැක."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ගොනු හුවමාරු විකල්ප"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"මධ්ය ධාවකයක් (MTP) ලෙස සවි කරන්න"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"කැමරාවක් (PTP) ලෙස සවි කරන්න"</string> @@ -166,18 +167,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"පැනලය වහන්න"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"වේලාව වැඩියෙන්"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"වේලාව අඩුවෙන්"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G දත්ත නැත"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G දත්ත නැත"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"සෙලියුලර් දත්ත අක්රියයි"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"දත්ත අක්රියයි"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ඔබ සකසන ලද දත්ත සීමාවට එය ළඟාවී ඇති නිසා ඔබගේ උපාංගයේ දත්ත අක්රිය කර ඇත.\n\nඑය නැවත සක්රිය කිරීමෙන් ඔබගේ වාහකය ඇතැම් විට අය කර ගැනීමට හේතු වේ."</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"දත්ත සක්රිය කරන්න"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS සඳහා සොයමින්"</string> @@ -255,16 +250,12 @@ <string name="description_target_search" msgid="3091587249776033139">"සෙවීම"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා උඩට සර්පණය කරන්න."</string> <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා වමට සර්පණය කරන්න."</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"සීනු ඇතුළුව, අතුරු බිඳීම් නැත"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"අතුරු බිදුම් නැත"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"ප්රමුඛ අතුරු බිඳීම් පමණයි"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"ඔබගේ ඊළඟ සීනුව <xliff:g id="ALARM_TIME">%s</xliff:g> තිබේ"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"ඔබගේ ඊළඟ සීනුව <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> වේ"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> හි තිබෙන ඔබගේ සීනුව ඔබට ඇසෙන්නේ නැත"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"හදිසිය අඩු දැනුම් දීම් පහත"</string> <string name="notification_tap_again" msgid="7590196980943943842">"විවෘත කිරීමට නැවත තට්ටු කරන්න"</string> @@ -278,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"අමුත්තා"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ අමුත්තා"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"අමුත්තා පිටවීම"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"විනාඩි එකක් සඳහා"</item> <item quantity="other" msgid="6924190729213550991">"විනාඩි %d සඳහා"</item> @@ -291,12 +295,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"බැටරි ඉතිරි කරන්නා සැකසීම් විවෘත කරන්න"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"සැඟවුණු සම්බන්ධතා"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"ඔබගේ තීරයේ දර්ශනය වන සෑම දෙයම <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ලබාගැනීම ආරම්භ කරන ලදි."</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"නැවත නොපෙන්වන්න"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"දැන් අරඹන්න"</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 08b6221bfd67..53f2564235df 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímka obrazovky bola zaznamenaná."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Snímku obrazovky zobrazíte dotykom."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Snímku obrazovky sa nepodarilo zachytiť."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Snímku obrazovky sa nepodarilo uložiť. Ukladací priestor sa možno práve používa."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosu súborov USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Pripojiť ako prehrávač médií (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Pripojiť ako fotoaparát (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Hosť"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Pridať hosťa"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Ukončiť režim hosťa"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Na jednu minútu"</item> <item quantity="other" msgid="6924190729213550991">"Na %d min"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otvorte nastavenia šetriča batérie"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Ukončiť režim hosťa"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávať všetok obsah zobrazený na vašej obrazovke."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Nabudúce nezobrazovať"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Spustiť"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index d73fff81f17c..22914b05c3b0 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Posnetek zaslona je shranjen."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Dotaknite se, če si želite ogledati posnetek zaslona."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Posnetka zaslona ni bilo mogoče shraniti."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Posnetka zaslona ni bilo mogoče shraniti. Shramba je morda v uporabi."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosa datotek prek USB-ja"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Vpni kot predvajalnik (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Vpni kot fotoaparat (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Dodajanje gosta"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Izhod iz načina za goste"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Za eno minuto"</item> <item quantity="other" msgid="6924190729213550991">"Za %d min"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Odpri nastavitve varčevanja z energijo akumulatorja"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Vsebina je skrita"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Izhod iz načina za goste"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bo začela zajemati vse, kar je prikazano na zaslonu."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Tega ne prikaži več"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Začni zdaj"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index f08af24f9d2c..fd66ff3321aa 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Снимак екрана је направљен."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Додирните да бисте видели снимак екрана."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Није могуће направити снимак екрана."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Није могуће сачувати снимак екрана. Могуће је да је меморија у употреби."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Опције USB преноса датотека"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Прикључи као медија плејер (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Прикључи као камеру (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Гост"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Изађи из режима госта"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Један минут"</item> <item quantity="other" msgid="6924190729213550991">"%d мин"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отворите подешавања Штедње батерије"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Садржај је сакривен"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Изађи из режима госта"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ће почети да снима све што се приказује на екрану."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Не приказуј поново"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Започни одмах"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 4e3caa179ce7..69c47e4e28f5 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Skärmdumpen har tagits."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Tryck här om du vill visa skärmdumpen."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Det gick inte att ta någon skärmdump."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Det gick inte att spara skärmdumpen. Extern lagring kanske används."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Överföringsalternativ"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Montera som mediaspelare (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Montera som kamera (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Gäst"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Lägg till gäst"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Avsluta gäst"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"I en minut"</item> <item quantity="other" msgid="6924190729213550991">"I %d minuter"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Öppna inställningarna för batterisparläget"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Innehåll har dolts"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Avsluta gäst"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar en bild av allt som visas på skärmen."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Visa inte igen"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Starta nu"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 9c3e05ae304b..9aa904962758 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -71,7 +71,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Picha ya skrini imenaswa."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Gusa ili kuona picha yako ya skrini."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Haikuweza kunasa picha ya skrini"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Haikuweza kuhifadhi picha ya skrini. Huenda hifadhi inatumika."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Machaguo ya uhamisho wa faili la USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Angika kama kichezeshi cha midia (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Angika kama kamera (PTP)"</string> @@ -168,7 +169,7 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data ya 4G imezimwa"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data ya simu ya mkononi imezimwa"</string> <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data imezimwa"</string> - <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Kifaa chako kilizima data kwa sababu kilifikia kikomo ulichoweka.\n\nKukiwasha tena kunaweza kupelekea utozwe na mtoa huduma wako."</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Kifaa chako kilizima data kwa sababu kilifikia kikomo ulichoweka.\n\nKuwasha data tena kunaweza kusababisha matozo kutoka kwa mtoa huduma wako."</string> <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Washa matumizi ya data"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string> @@ -247,7 +248,7 @@ <string name="description_target_search" msgid="3091587249776033139">"Tafuta"</string> <string name="description_direction_up" msgid="7169032478259485180">"Sogeza juu kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> <string name="description_direction_left" msgid="7207478719805562165">"Sogeza kushoto kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> - <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Hakuna katizo, ikiwa ni pamoja na kengele"</string> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Hakuna kukatizwa, hata kutoka kwenye kengele"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"Hakuna katizo"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"Katizo za kipaumbele pekee"</string> <string name="zen_alarm_information_time" msgid="5235772206174372272">"Kengele yako inayofuata itakuwa saa <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> @@ -266,6 +267,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji ( <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hadi ijae)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Aliyealikwa"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Aliyealikwa"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Ondoa aliyealikwa"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Kwa dakika moja"</item> <item quantity="other" msgid="6924190729213550991">"Kwa dakika %d"</item> @@ -279,7 +293,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Fungua mipangilio ya hali inayookoa betri"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Maudhui yamefichwa"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Ondoa aliyealikwa"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> itaanza kupiga picha kila kitu kinachoonyeshwa kwenye skrini yako."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Usionyeshe tena"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Anza sasa"</string> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index a5e392406a60..953a3abe8d0d 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -62,4 +62,22 @@ keyguard_clock_height_fraction_* for the difference between min and max.--> <dimen name="keyguard_clock_notifications_margin_min">44dp</dimen> <dimen name="keyguard_clock_notifications_margin_max">44dp</dimen> + + <!-- Height of the status bar header bar when on Keyguard --> + <dimen name="status_bar_header_height_keyguard">60dp</dimen> + + <!-- The width of user avatar when on Keyguard --> + <dimen name="multi_user_switch_width_keyguard">48dp</dimen> + + <!-- The width of user avatar when on Keyguard --> + <dimen name="multi_user_avatar_keyguard_size">30dp</dimen> + + <!-- end margin for multi user switch in collapsed quick settings --> + <dimen name="multi_user_switch_keyguard_margin">6dp</dimen> + + <!-- Margin on the left side of the carrier text on Keyguard --> + <dimen name="keyguard_carrier_text_margin">24dp</dimen> + + <!-- end margin for system icons if multi user switch is hidden --> + <dimen name="system_icons_switcher_hidden_expanded_margin">20dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml index ab76f71571c0..e9b0394aef6d 100644 --- a/packages/SystemUI/res/values-ta-rIN/strings.xml +++ b/packages/SystemUI/res/values-ta-rIN/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"உங்கள் ஸ்க்ரீன் ஷாட்டைப் பார்க்க தொடவும்."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"ஸ்க்ரீன் ஷாட்டை எடுக்க முடியவில்லை."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"ஸ்கீர்ன் ஷாட்டைச் சேமிக்க முடியவில்லை. சேமிப்பிடம் பயன்பாட்டில் இருக்கலாம்."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB கோப்பு இடமாற்ற விருப்பங்கள்"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"(MTP) மீடியா பிளேயராக ஏற்று"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"(PTP) கேமராவாக ஏற்று"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"சார்ஜாகிறது (முழு சார்ஜிற்கு <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ஆகும்)"</string> <string name="guest_nickname" msgid="8059989128963789678">"அழைக்கப்பட்டவர்"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ அழைக்கப்பட்டவர்"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"விருந்தினரிலிருந்து வெளியேறு"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ஒரு நிமிடம்"</item> <item quantity="other" msgid="6924190729213550991">"%d நிமிடங்கள்"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"பேட்டரி சேமிப்பான் அமைப்புகளைத் திற"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"மறைந்துள்ள உள்ளடக்கம்"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"விருந்தினரிலிருந்து வெளியேறு"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"திரையில் காட்டப்படும் அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> படமெடுக்கும்."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"மீண்டும் காட்டாதே"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"இப்போது தொடங்கு"</string> diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml index cbab00ff3c99..687a110877f9 100644 --- a/packages/SystemUI/res/values-te-rIN/strings.xml +++ b/packages/SystemUI/res/values-te-rIN/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"స్క్రీన్షాట్ క్యాప్చర్ చేయబడింది."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"మీ స్క్రీన్షాట్ను వీక్షించడానికి తాకండి."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"స్క్రీన్షాట్ను క్యాప్చర్ చేయడం సాధ్యపడలేదు."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"స్క్రీన్షాట్ను సేవ్ చేయడం సాధ్యపడలేదు. నిల్వ ఉపయోగంలో ఉండవచ్చు."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB ఫైల్ బదిలీ ఎంపికలు"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"మీడియా ప్లేయర్గా (MTP) మౌంట్ చేయి"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"కెమెరాగా (PTP) మౌంట్ చేయి"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ఛార్జ్ అవుతోంది (పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="guest_nickname" msgid="8059989128963789678">"అతిథి"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ అతిథి"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"అతిథి మోడ్ నుండి నిష్క్రమించండి"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ఒక నిమిషానికి"</item> <item quantity="other" msgid="6924190729213550991">"%d నిమిషాలకి"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"బ్యాటరీ సేవర్ సెట్టింగ్లను తెరువు"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"కంటెంట్లు దాచబడ్డాయి"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"అతిథి మోడ్ నుండి నిష్క్రమించండి"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> మీ స్క్రీన్పై కనిపించే ప్రతిదాన్ని క్యాప్చర్ చేయడం ప్రారంభిస్తుంది."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"మళ్లీ చూపవద్దు"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"ఇప్పుడే ప్రారంభించు"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 215d3e12fb3d..4f2cb6f4d271 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"จับภาพหน้าจอแล้ว"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"แตะเพื่อดูภาพหน้าจอของคุณ"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"ไม่สามารถจับภาพหน้าจอ"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"ไม่สามารถบันทึกภาพหน้าจอ ที่จัดเก็บข้อมูลอาจมีการใช้งานอยู่"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"ตัวเลือกการถ่ายโอนไฟล์ USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"ต่อเชื่อมเป็นโปรแกรมเล่นสื่อ (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"ต่อเชื่อมเป็นกล้องถ่ายรูป (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string> <string name="guest_nickname" msgid="8059989128963789678">"ผู้เข้าร่วม"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ ผู้เข้าร่วม"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"ออกจากโหมดผู้เยี่ยมชม"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 นาที"</item> <item quantity="other" msgid="6924190729213550991">"%d นาที"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"เปิดการตั้งค่าโหมดประหยัดแบตเตอรี่"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"เนื้อหาที่ซ่อน"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"ออกจากโหมดผู้เยี่ยมชม"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะเริ่มจับภาพทุกอย่างที่แสดงบนหน้าจอ"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"ไม่ต้องแสดงข้อความนี้อีก"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"เริ่มเลย"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 9387e9edfb09..4a6007c6345e 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Nakuha ang screenshot."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Pindutin upang tingnan ang iyong screenshot."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Hindi makuha ang screenshot."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Hindi ma-save ang screenshot. Maaaring ginagamit ang storage."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Opsyon paglipat ng USB file"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"I-mount bilang isang media player (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"I-mount bilang camera (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Bisita"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Bisita"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Lumabas bilang guest"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Sa loob ng isang minuto"</item> <item quantity="other" msgid="6924190729213550991">"Sa loob ng %d (na) minuto"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buksan ang mga setting ng tagatipid ng baterya"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Nakatago ang mga content"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Lumabas bilang guest"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"Sisimulan ng i-capture ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang lahat ng ipinapakita sa iyong screen."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Huwag ipakitang muli"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Magsimula ngayon"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index c00ec90d6d72..7938f3d09f15 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran görüntüsü alındı."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Ekran görüntünüzü izlemek için dokunun."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Ekran görüntüsü alınamadı."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Ekran görüntüsü kaydedilemedi. Depolama birimi kullanımda olabilir."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB dosya aktarım seçenekleri"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Medya oynatıcı olarak ekle (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera olarak ekle (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Misafir"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Misafir"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Misafir oturumundan çık"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Bir dakika süreyle"</item> <item quantity="other" msgid="6924190729213550991">"%d dakika süreyle"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Pil tasarrufu ayarlarını aç"</string> <string name="battery_level_template" msgid="1609636980292580020">"%%<xliff:g id="LEVEL">%d</xliff:g>"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"İçerik gizlendi"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Misafir oturumundan çık"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ekranınızda görüntülenen her şeyi kaydetmeye başlayacak."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Bir daha gösterme"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Şimdi başla"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 49abb629285a..c2259f83ef1c 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Знімок екрана зроблено."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Торкніться, щоб переглянути знімок екрана."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Не вдалося зробити знімок екрана."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Не вдалося зберегти знімок екрана. Можливо, пам’ять використовується."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Парам.передав.файлів через USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Підключити як медіапрогравач (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Підключити як камеру (PTP)"</string> @@ -170,7 +171,7 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Дані 4G вимкнено"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобільні дані вимкнено"</string> <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дані вимкнено"</string> - <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Пристрій вимкнув передавання даних, оскільки на ньому досягнуто встановленого вами ліміту.\n\nЯкщо передавання даних знову ввімкнути, оператор може стягувати з вас плату за це."</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Пристрій вимкнув передавання даних, оскільки перевищено встановлений вами ліміт.\n\nЯкщо передавання даних знову ввімкнути, оператор може стягувати додаткову плату."</string> <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Увімкнути дані"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Гість"</string> <string name="guest_new_guest" msgid="4259024453643879653">"Додати гостя"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Вийти з режиму гостя"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Протягом хвилини"</item> <item quantity="other" msgid="6924190729213550991">"Протягом %d хв"</item> @@ -281,8 +295,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Відкрийте налаштування режиму заощадження заряду акумулятора"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Вміст сховано"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Вийти з гостьового режиму"</string> - <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> почне збирати всі дані, які відображаються на вашому екрані."</string> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> отримає доступ до всіх даних, які відображаються на вашому екрані."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Більше не показувати"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Почати зараз"</string> </resources> diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml index aa15d23bca66..e2e17046aafe 100644 --- a/packages/SystemUI/res/values-ur-rPK/strings.xml +++ b/packages/SystemUI/res/values-ur-rPK/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"اسکرین شاٹ کیپچر کیا گیا۔"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"اپنے اسکرین شاٹ دیکھنے کیلئے چھوئیں۔"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"اسکرین شاٹ کیپچر نہیں کر سکے۔"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"اسکرین شاٹ محفوظ نہیں کر سکے۔ ممکن ہے اسٹوریج کا استعمال ہو رہا ہے۔"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB فائل منتقل کرنیکے اختیارات"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"ایک میڈیا پلیئر (MTP) کے بطور ماؤنٹ کریں"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"ایک کیمرہ (PTP) کے بطور ماؤنٹ کریں"</string> @@ -170,7 +171,7 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ڈیٹا آف ہے"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"سیلولر ڈیٹا آف ہے"</string> <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ڈیٹا آف ہے"</string> - <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"آپ کے آلہ نے ڈیٹا کو آف کر دیا کیونکہ یہ آپ کے متعینہ حد کو پہنچ گیا ہے۔\n\nاسے دوبارہ آن کرنے سے آپ کے کیریئر کی جانب سے چارجز عائد ہو سکتے ہیں۔"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"آپ کے آلہ نے ڈیٹا کو آف کر دیا کیونکہ یہ آپ کی متعینہ حد کو پہنچ گیا۔\n\nاسے دوبارہ آن کرنے سے آپ کے کیریئر کی جانب سے چارجز عائد ہو سکتے ہیں۔"</string> <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ڈیٹا آن کریں"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi مربوط ہے"</string> @@ -252,9 +253,9 @@ <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"الارمز کے بشمول، کوئی مداخلتیں نہیں ہیں"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"کوئی مداخلتیں نہیں ہیں"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"صرف ترجیحی مداخلتیں"</string> - <string name="zen_alarm_information_time" msgid="5235772206174372272">"آپ کا اگلا الارم بوقت <xliff:g id="ALARM_TIME">%s</xliff:g> ہے"</string> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"آپ کا اگلا الارم <xliff:g id="ALARM_TIME">%s</xliff:g> بجے ہے"</string> <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"آپ کا اگلا الارم <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> ہے"</string> - <string name="zen_alarm_warning" msgid="6873910860111498041">"آپ کو بوقت <xliff:g id="ALARM_TIME">%s</xliff:g> اپنا الارم سنائی نہیں دیگا"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"آپ کو <xliff:g id="ALARM_TIME">%s</xliff:g> بجے اپنا الارم سنائی نہیں دیگا"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"کم اہم اطلاعات ذیل میں ہیں"</string> <string name="notification_tap_again" msgid="7590196980943943842">"کھولنے کیلئے دوبارہ تھپتھپائیں"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"چارج ہو رہا ہے (مکمل ہونے تک <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> باقی ہیں)"</string> <string name="guest_nickname" msgid="8059989128963789678">"مہمان"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ مہمان"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"مہمان وضع سے باہر نکلیں"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ایک منٹ کیلئے"</item> <item quantity="other" msgid="6924190729213550991">"%d منٹ کیلئے"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"بیٹری سیور کی ترتیبات کھولیں"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"مواد مخفی ہیں"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"مہمان سے باہر نکلیں"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> آپ کی اسکرین پر ڈسپلے ہونے والی ہر چیز کو کیپچر کرنا شروع کر دیگی۔"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"دوبارہ نہ دکھائیں"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"ابھی شروع کریں"</string> diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml index 7a551d392579..cdc55e6544e3 100644 --- a/packages/SystemUI/res/values-uz-rUZ/strings.xml +++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran surati olindi."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Ekraningiz suratini ko‘rish uchun bosing."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Ekran surati olinmadi."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Ekran surati saqlanmadi. Xotiradan foydalanilayotgan bo‘lishi mumkin."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB fayl ko‘chirish moslamalari"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer sifatida ulash (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera sifatida ulash (PTP)"</string> @@ -166,18 +167,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Panelni yopish"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Vaqtni ko‘paytirish"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Vaqtni kamaytirish"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G internet o‘chirib qo‘yildi"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G internet o‘chirib qo‘yildi"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobil internet o‘chirib qo‘yildi"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Internet o‘chirib qo‘yildi"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Siz o‘rnatgan chegaraga yetib kelgani tufayli qurilmangizda internet o‘chirib qo‘yildi.\n\nUni qayta yoqishingiz mumkin, biroq buning uchun aloqa operatoringiz qo‘shimcha haq olishi mumkin."</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Internetni yoqish"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS qidirilmoqda"</string> @@ -255,16 +250,12 @@ <string name="description_target_search" msgid="3091587249776033139">"Izlash"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun yuqoriga suring."</string> <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun chapga suring."</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"“Bezovta qilmaslik” rejimi (uyg‘otkich ovozi o‘chirilgan)"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"Tanaffuslarsiz"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"Faqat ustuvor tanaffuslar"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"Keyingi uyg‘otkich: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Keyingi uyg‘otkich: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"Keyingi uyg‘otkich: <xliff:g id="ALARM_TIME">%s</xliff:g>. Ovoz eshitilmaydi."</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"Kam ahamiyatli bildirishnomalarni pastda ko‘rsatish"</string> <string name="notification_tap_again" msgid="7590196980943943842">"Ochish uchun yana bosing"</string> @@ -278,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Quvvat olmoqda (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>da to‘ladi)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Mehmon"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Mehmon"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Mehmon rejimidan chiqish"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 daqiqa"</item> <item quantity="other" msgid="6924190729213550991">"%d daqiqa"</item> @@ -291,12 +295,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Quvvat tejash sozlamalarini ochish"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Kontent yashirildi"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi qurilma ekranidagi har qanday tasvirni ko‘rishni boshlaydi."</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"Boshqa ko‘rsatilmasin"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"Boshlash"</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index bf32e6c40cd8..c39ec022f0b9 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Đã chụp ảnh màn hình."</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Chạm để xem ảnh chụp màn hình của bạn."</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Không thể chụp ảnh màn hình."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Không thể lưu ảnh chụp màn hình. Bộ lưu trữ có thể đang được sử dụng."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Tùy chọn truyền tệp USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Gắn như một trình phát đa phương tiện (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Gắn như một máy ảnh (PTP)"</string> @@ -170,7 +171,7 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Dữ liệu 4G bị tắt"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Dữ liệu di động bị tắt"</string> <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dữ liệu bị tắt"</string> - <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Thiết bị của bạn bị tắt dữ liệu do đã đạt đến giới hạn bạn đã đặt.\n\nViệc bật lại dữ liệu có thể dẫn tới các khoản phí từ nhà cung cấp dịch vụ của bạn."</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Thiết bị của bạn đã tắt dữ liệu do đã đạt đến giới hạn bạn đã đặt.\n\nViệc bật lại dữ liệu có thể dẫn tới các khoản phí từ nhà cung cấp dịch vụ của bạn."</string> <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Bật dữ liệu"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Khách"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Khách"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Thoát chế độ khách"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Trong một phút"</item> <item quantity="other" msgid="6924190729213550991">"Trong %d phút"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Mở cài đặt trình tiết kiệm pin"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Nội dung bị ẩn"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Thoát chế độ khách"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ bắt đầu chụp mọi thứ hiển thị trên màn hình."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Không hiển thị lại"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Bắt đầu ngay"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 92ee5a298b56..111e0a2ffd47 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"已抓取屏幕截图。"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"触摸可查看您的屏幕截图。"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"无法抓取屏幕截图。"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"无法保存屏幕截图。存储设备可能正在使用中。"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB 文件传输选项"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"作为媒体播放器 (MTP) 装载"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"作为摄像头 (PTP) 装载"</string> @@ -138,7 +139,7 @@ <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"漫游中"</string> <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"EDGE"</string> <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"WLAN"</string> - <string name="accessibility_no_sim" msgid="8274017118472455155">"无 SIM 卡。"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"无SIM卡。"</string> <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"蓝牙网络共享。"</string> <string name="accessibility_airplane_mode" msgid="834748999790763092">"飞行模式。"</string> <!-- String.format failed for translation --> @@ -168,18 +169,12 @@ <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"关闭面板"</string> <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"更长时间"</string> <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"更短时间"</string> - <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) --> - <skip /> - <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) --> - <skip /> + <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G数据网络已关闭"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G数据网络已关闭"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"移动数据网络已关闭"</string> + <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"数据网络已关闭"</string> + <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"由于数据流量已达到您所设置的上限,因此您的设备已关闭数据网络。\n\n如果重新开启数据网络,那么您的运营商可能会向您收取相应费用。"</string> + <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"开启数据网络"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN 已连接"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜索 GPS"</string> @@ -257,16 +252,12 @@ <string name="description_target_search" msgid="3091587249776033139">"搜索"</string> <string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string> <string name="description_direction_left" msgid="7207478719805562165">"向左滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string> - <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) --> - <skip /> + <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"禁止打扰(包括闹钟)"</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"禁止打扰"</string> <string name="zen_important_interruptions" msgid="3477041776609757628">"仅限优先打扰内容"</string> - <!-- no translation found for zen_alarm_information_time (5235772206174372272) --> - <skip /> - <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) --> - <skip /> - <!-- no translation found for zen_alarm_warning (6873910860111498041) --> - <skip /> + <string name="zen_alarm_information_time" msgid="5235772206174372272">"下次闹钟响铃时间:<xliff:g id="ALARM_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"下次闹钟响铃时间:<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> + <string name="zen_alarm_warning" msgid="6873910860111498041">"您在<xliff:g id="ALARM_TIME">%s</xliff:g>将不会听到闹钟响铃"</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"不太紧急的通知会显示在下方"</string> <string name="notification_tap_again" msgid="7590196980943943842">"再次点按即可打开"</string> @@ -280,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string> <string name="guest_nickname" msgid="8059989128963789678">"访客"</string> <string name="guest_new_guest" msgid="4259024453643879653">"添加新访客"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"退出访客模式"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1分钟"</item> <item quantity="other" msgid="6924190729213550991">"%d分钟"</item> @@ -293,12 +297,7 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"打开节电助手设置"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</string> - <!-- no translation found for guest_exit_guest (1619100760451149682) --> - <skip /> - <!-- no translation found for media_projection_dialog_text (3071431025448218928) --> - <skip /> - <!-- no translation found for media_projection_remember_text (3103510882172746752) --> - <skip /> - <!-- no translation found for media_projection_action_text (8470872969457985954) --> - <skip /> + <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>将开始截取您的屏幕上显示的所有内容。"</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"不再显示"</string> + <string name="media_projection_action_text" msgid="8470872969457985954">"立即开始"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 2e3878d69517..298aac13a5fe 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"已擷取螢幕畫面。"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"輕觸即可查看螢幕擷取畫面。"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"無法擷取螢幕畫面。"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"無法儲存螢幕擷取畫面,儲存裝置可能正在使用。"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string> <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string> <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"結束訪客模式"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item> <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"開啟省電設定"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"結束訪客模式"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"不用再顯示"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"立即開始"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 840778b26e7f..d766acabe52f 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"已拍攝螢幕擷取畫面。"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"輕觸即可查看螢幕擷取畫面。"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"無法拍攝螢幕擷取畫面。"</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"無法儲存螢幕擷取畫面,儲存空間可能正在使用中。"</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string> @@ -270,6 +271,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string> <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string> <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"結束訪客模式"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item> <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item> @@ -283,7 +297,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"開啟節約耗電量設定"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"結束訪客模式"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"不要再顯示"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"立即開始"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 38e4d8fad8b1..7e49f6ebe844 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -73,7 +73,8 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Umfanekiso weskrini uqoshiwe"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Thinta ukubona imifanekiso yakho yeskrini"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Yehlulekile ukulondoloza umfanekiso weskrini."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Ayikwazanga ukulondoloza isithombe-skrini. Isitoreji sangaphandle kungenzeka kuyasetshenziswa."</string> + <!-- no translation found for screenshot_failed_text (1260203058661337274) --> + <skip /> <string name="usb_preference_title" msgid="6551050377388882787">"Okukhethwa kokudluliswa kwefayela ye-USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Lengisa njengesidlali semediya (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Lengisa ikhamera (PTP)"</string> @@ -268,6 +269,19 @@ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string> <string name="guest_nickname" msgid="8059989128963789678">"Isihambeli"</string> <string name="guest_new_guest" msgid="4259024453643879653">"+ Isihambeli"</string> + <string name="guest_exit_guest" msgid="1619100760451149682">"Phuma kusivakashi"</string> + <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) --> + <skip /> + <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) --> + <skip /> + <!-- no translation found for guest_wipe_session_title (6419439912885956132) --> + <skip /> + <!-- no translation found for guest_wipe_session_message (5369763062345463297) --> + <skip /> + <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) --> + <skip /> + <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) --> + <skip /> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Iminithi elilodwa"</item> <item quantity="other" msgid="6924190729213550991">"Amaminithi angu-%d"</item> @@ -281,7 +295,6 @@ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Vula izilungiselelo zesilondolozi sebhethri"</string> <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Okuqukethwe kufihliwe"</string> - <string name="guest_exit_guest" msgid="1619100760451149682">"Phuma kusivakashi"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> izoqala ukuthwebula yonke into eboniswa kusikrini sakho."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"Ungabonisi futhi"</string> <string name="media_projection_action_text" msgid="8470872969457985954">"Qala manje"</string> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index e9fe09e4a064..a718f4fe0e45 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -62,7 +62,7 @@ <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. --> <color name="recents_task_bar_light_dismiss_color">#ffeeeeee</color> <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. --> - <color name="recents_task_bar_dark_dismiss_color">#cc000000</color> + <color name="recents_task_bar_dark_dismiss_color">#99000000</color> <!-- The recents task bar highlight color. --> <color name="recents_task_bar_highlight_color">#28ffffff</color> <!-- The lock to task button background color. --> @@ -94,4 +94,10 @@ <color name="current_user_border_color">@color/system_accent_color</color> <color name="segmented_button_text_inactive">#99afbdc4</color><!-- 60% --> + + <!-- The "inside" of a notification, reached via longpress --> + <color name="notification_guts_bg_color">#ff424242</color><!-- grey 800 --> + <color name="notification_guts_title_color">#FFFFFFFF</color> + <color name="notification_guts_text_color">#99FFFFFF</color> + <color name="notification_guts_btn_color">#FFFFFFFF</color> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 9bc2b0d331c4..bd10623712dd 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -295,6 +295,15 @@ <!-- The minimum amount the user needs to swipe to go to the camera / phone. --> <dimen name="keyguard_min_swipe_amount">75dp</dimen> + <!-- The minimum background radius when swiping to a side for the camera / phone affordances. --> + <dimen name="keyguard_affordance_min_background_radius">30dp</dimen> + + <!-- The grow amount for the camera and phone circles when hinting --> + <dimen name="hint_grow_amount_sideways">60dp</dimen> + + <!-- The chevron padding to the circle when hinting --> + <dimen name="hint_chevron_circle_padding">16dp</dimen> + <!-- Volume panel dialog y offset --> <dimen name="volume_panel_top">0dp</dimen> @@ -317,9 +326,6 @@ <!-- Move distance for the unlock hint animation on the lockscreen --> <dimen name="hint_move_distance">75dp</dimen> - <!-- Move distance for the other hint animations on the lockscreen (phone, camera)--> - <dimen name="hint_move_distance_sideways">60dp</dimen> - <!-- The width of the region on the left/right edge of the screen for performing the camera/ phone hints. --> <dimen name="edge_tap_area_width">48dp</dimen> @@ -347,15 +353,24 @@ <!-- The padding bottom of the clock group when QS is expanded. --> <dimen name="clock_expanded_bottom_margin">20dp</dimen> + <!-- The padding bottom of the clock group when QS is collapsed. --> + <dimen name="clock_collapsed_bottom_margin">10dp</dimen> + <!-- The width of the multi user switch on keyguard and collapsed QS header. --> <dimen name="multi_user_switch_width_collapsed">34dp</dimen> <!-- The width of the multi user switch in expanded QS header. --> <dimen name="multi_user_switch_width_expanded">48dp</dimen> + <!-- The width of user avatar when on Keyguard --> + <dimen name="multi_user_switch_width_keyguard">34dp</dimen> + <!-- The width of user avatar when collapsed --> <dimen name="multi_user_avatar_collapsed_size">22dp</dimen> + <!-- The width of user avatar when on Keyguard --> + <dimen name="multi_user_avatar_keyguard_size">22dp</dimen> + <!-- The font size of the time when collapsed in QS --> <dimen name="qs_time_collapsed_size">14sp</dimen> @@ -365,7 +380,19 @@ <!-- Battery level padding end when in expanded QS (but not on Keyguard) --> <dimen name="battery_level_padding_end">4dp</dimen> + <!-- The top padding of the clear all button --> + <dimen name="clear_all_padding_top">4dp</dimen> + <!-- Largest size an avatar might need to be drawn in the user picker, status bar, or quick settings header --> <dimen name="max_avatar_size">48dp</dimen> + + <!-- Margin on the left side of the carrier text on Keyguard --> + <dimen name="keyguard_carrier_text_margin">16dp</dimen> + + <!-- Margin on the left side of the battery % in the header. --> + <dimen name="header_battery_margin_expanded">8dp</dimen> + + <!-- Margin on the left side of the battery % when on Keyguard. --> + <dimen name="header_battery_margin_keyguard">6dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 416cd542932c..085d2f9953ba 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -380,8 +380,12 @@ <!-- Content description of the ringer silent icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_ringer_silent">Ringer silent.</string> + <!-- Content description to tell the user that this button will remove an application from recents --> + <string name="accessibility_recents_item_will_be_dismissed">Dismiss <xliff:g id="app" example="Calendar">%s</xliff:g>.</string> <!-- Content description to tell the user an application has been removed from recents --> <string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string> + <!-- Content description to tell the user an application has been launched from recents --> + <string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string> <!-- Content description to tell the user a notification has been removed from the notification shade --> <string name="accessibility_notification_dismissed">Notification dismissed.</string> @@ -732,6 +736,12 @@ <!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] --> <string name="media_projection_remember_text">Don\'t show again</string> + <!-- The text to clear all notifications. [CHAR LIMIT=60] --> + <string name="clear_all_notifications_text">Clear all</string> + <!-- Media projection permission dialog action text. [CHAR LIMIT=60] --> <string name="media_projection_action_text">Start now</string> + + <!-- Text which is shown in the notification shade when there are no notifications. [CHAR LIMIT=30] --> + <string name="empty_shade_text">No notifications</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 0b8f876b946e..61e6121a9a6c 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -249,6 +249,11 @@ <item name="android:colorControlActivated">@color/system_accent_color</item> </style> + <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog"> + <item name="android:colorPrimary">@color/system_primary_color</item> + <item name="android:colorControlActivated">@color/system_accent_color</item> + </style> + <style name="NotificationsQuickSettings"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">match_parent</item> @@ -275,7 +280,4 @@ <item name="android:textStyle">italic</item> <item name="android:textColor">#60000000</item> </style> - - <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog"> - </style> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 5e482588527f..b9ffdbb929e1 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -402,6 +402,11 @@ public class BatteryMeterView extends View implements DemoMode { } } + @Override + public boolean hasOverlappingRendering() { + return false; + } + private boolean mDemoMode; private BatteryTracker mDemoTracker = new BatteryTracker(); diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index bbda536d2198..a26c5343055b 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -29,11 +29,13 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector.OnScaleGestureListener; +import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.ExpandableView; +import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.policy.ScrollAdapter; public class ExpandHelper implements Gefingerpoken { @@ -49,7 +51,7 @@ public class ExpandHelper implements Gefingerpoken { private static final String TAG = "ExpandHelper"; protected static final boolean DEBUG = false; protected static final boolean DEBUG_SCALE = false; - private static final long EXPAND_DURATION = 250; + private static final float EXPAND_DURATION = 0.3f; // Set to false to disable focus-based gestures (spread-finger vertical pull). private static final boolean USE_DRAG = true; @@ -112,6 +114,8 @@ public class ExpandHelper implements Gefingerpoken { private int mGravity; private ScrollAdapter mScrollAdapter; + private FlingAnimationUtils mFlingAnimationUtils; + private VelocityTracker mVelocityTracker; private OnScaleGestureListener mScaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() { @@ -171,7 +175,6 @@ public class ExpandHelper implements Gefingerpoken { mScaler = new ViewScaler(); mGravity = Gravity.TOP; mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f); - mScaleAnimation.setDuration(EXPAND_DURATION); mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms); mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min); @@ -179,6 +182,7 @@ public class ExpandHelper implements Gefingerpoken { mTouchSlop = configuration.getScaledTouchSlop(); mSGD = new ScaleGestureDetector(context, mScaleGestureListener); + mFlingAnimationUtils = new FlingAnimationUtils(context, EXPAND_DURATION); } private void updateExpansion() { @@ -260,6 +264,7 @@ public class ExpandHelper implements Gefingerpoken { if (!isEnabled()) { return false; } + trackVelocity(ev); final int action = ev.getAction(); if (DEBUG_SCALE) Log.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) + " expanding=" + mExpanding + @@ -279,6 +284,7 @@ public class ExpandHelper implements Gefingerpoken { if (mExpanding) { mLastMotionY = ev.getRawY(); + maybeRecycleVelocityTracker(ev); return true; } else { if ((action == MotionEvent.ACTION_MOVE) && 0 != (mExpansionStyle & BLINDS)) { @@ -323,15 +329,52 @@ public class ExpandHelper implements Gefingerpoken { case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: if (DEBUG) Log.d(TAG, "up/cancel"); - finishExpanding(false); + finishExpanding(false, getCurrentVelocity()); clearView(); break; } mLastMotionY = ev.getRawY(); + maybeRecycleVelocityTracker(ev); return mExpanding; } } + private void trackVelocity(MotionEvent event) { + int action = event.getActionMasked(); + switch(action) { + case MotionEvent.ACTION_DOWN: + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + mVelocityTracker.addMovement(event); + break; + case MotionEvent.ACTION_MOVE: + mVelocityTracker.addMovement(event); + break; + default: + break; + } + } + + private void maybeRecycleVelocityTracker(MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_CANCEL + || event.getActionMasked() == MotionEvent.ACTION_UP) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + private float getCurrentVelocity() { + if (mVelocityTracker != null) { + mVelocityTracker.computeCurrentVelocity(1000); + return mVelocityTracker.getYVelocity(); + } else { + return 0f; + } + } + public void setEnabled(boolean enable) { mEnabled = enable; } @@ -349,6 +392,7 @@ public class ExpandHelper implements Gefingerpoken { if (!isEnabled()) { return false; } + trackVelocity(ev); final int action = ev.getActionMasked(); if (DEBUG_SCALE) Log.d(TAG, "touch: act=" + MotionEvent.actionToString(action) + " expanding=" + mExpanding + @@ -438,11 +482,12 @@ public class ExpandHelper implements Gefingerpoken { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (DEBUG) Log.d(TAG, "up/cancel"); - finishExpanding(false); + finishExpanding(false, getCurrentVelocity()); clearView(); break; } mLastMotionY = ev.getRawY(); + maybeRecycleVelocityTracker(ev); return mResizedView != null; } @@ -476,7 +521,7 @@ public class ExpandHelper implements Gefingerpoken { return true; } - private void finishExpanding(boolean force) { + private void finishExpanding(boolean force, float velocity) { if (!mExpanding) return; if (DEBUG) Log.d(TAG, "scale in finishing on view: " + mResizedView); @@ -506,6 +551,7 @@ public class ExpandHelper implements Gefingerpoken { mScaleAnimation.removeListener(this); } }); + mFlingAnimationUtils.apply(mScaleAnimation, currentHeight, targetHeight, velocity); mScaleAnimation.start(); } else { mCallback.setUserLockedChild(mResizedView, false); @@ -529,7 +575,7 @@ public class ExpandHelper implements Gefingerpoken { * Use this to abort any pending expansions in progress. */ public void cancel() { - finishExpanding(true); + finishExpanding(true, 0f /* velocity */); clearView(); // reset the gesture detector diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index d153d09766f4..6c30c898396d 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; import android.graphics.RectF; import android.os.Handler; import android.util.Log; @@ -29,6 +30,8 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; public class SwipeHelper implements Gefingerpoken { @@ -44,6 +47,7 @@ public class SwipeHelper implements Gefingerpoken { public static final int Y = 1; private static LinearInterpolator sLinearInterpolator = new LinearInterpolator(); + private final Interpolator mFastOutLinearInInterpolator; private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms @@ -72,23 +76,26 @@ public class SwipeHelper implements Gefingerpoken { private float mDensityScale; private boolean mLongPressSent; - private View.OnLongClickListener mLongPressListener; + private LongPressListener mLongPressListener; private Runnable mWatchLongPress; private long mLongPressTimeout; - public SwipeHelper(int swipeDirection, Callback callback, float densityScale, - float pagingTouchSlop) { + final private int[] mTmpPos = new int[2]; + + public SwipeHelper(int swipeDirection, Callback callback, Context context) { mCallback = callback; mHandler = new Handler(); mSwipeDirection = swipeDirection; mVelocityTracker = VelocityTracker.obtain(); - mDensityScale = densityScale; - mPagingTouchSlop = pagingTouchSlop; + mDensityScale = context.getResources().getDisplayMetrics().density; + mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop(); mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press! + mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, + android.R.interpolator.fast_out_linear_in); } - public void setLongPressListener(View.OnLongClickListener listener) { + public void setLongPressListener(LongPressListener listener) { mLongPressListener = listener; } @@ -210,7 +217,7 @@ public class SwipeHelper implements Gefingerpoken { } } - public boolean onInterceptTouchEvent(MotionEvent ev) { + public boolean onInterceptTouchEvent(final MotionEvent ev) { final int action = ev.getAction(); switch (action) { @@ -232,8 +239,12 @@ public class SwipeHelper implements Gefingerpoken { public void run() { if (mCurrView != null && !mLongPressSent) { mLongPressSent = true; - mCurrView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); - mLongPressListener.onLongClick(mCurrView); + mCurrView.sendAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); + mCurrView.getLocationOnScreen(mTmpPos); + final int x = (int) ev.getRawX() - mTmpPos[0]; + final int y = (int) ev.getRawY() - mTmpPos[1]; + mLongPressListener.onLongPress(mCurrView, x, y); } } }; @@ -262,14 +273,16 @@ public class SwipeHelper implements Gefingerpoken { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: + final boolean captured = (mDragging || mLongPressSent); mDragging = false; mCurrView = null; mCurrAnimView = null; mLongPressSent = false; removeLongPressCallback(); + if (captured) return true; break; } - return mDragging; + return mDragging || mLongPressSent; } /** @@ -277,6 +290,19 @@ public class SwipeHelper implements Gefingerpoken { * @param velocity The desired pixels/second speed at which the view should move */ public void dismissChild(final View view, float velocity) { + dismissChild(view, velocity, null, 0, false, 0); + } + + /** + * @param view The view to be dismissed + * @param velocity The desired pixels/second speed at which the view should move + * @param endAction The action to perform at the end + * @param delay The delay after which we should start + * @param useAccelerateInterpolator Should an accelerating Interpolator be used + * @param fixedDuration If not 0, this exact duration will be taken + */ + public void dismissChild(final View view, float velocity, final Runnable endAction, + long delay, boolean useAccelerateInterpolator, long fixedDuration) { final View animView = mCallback.getChildContentView(view); final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view); float newPos; @@ -289,22 +315,38 @@ public class SwipeHelper implements Gefingerpoken { } else { newPos = getSize(animView); } - int duration = MAX_ESCAPE_ANIMATION_DURATION; - if (velocity != 0) { - duration = Math.min(duration, - (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math - .abs(velocity))); + long duration; + if (fixedDuration == 0) { + duration = MAX_ESCAPE_ANIMATION_DURATION; + if (velocity != 0) { + duration = Math.min(duration, + (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math + .abs(velocity)) + ); + } else { + duration = DEFAULT_ESCAPE_ANIMATION_DURATION; + } } else { - duration = DEFAULT_ESCAPE_ANIMATION_DURATION; + duration = fixedDuration; } animView.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator anim = createTranslationAnimation(animView, newPos); - anim.setInterpolator(sLinearInterpolator); + if (useAccelerateInterpolator) { + anim.setInterpolator(mFastOutLinearInInterpolator); + } else { + anim.setInterpolator(sLinearInterpolator); + } anim.setDuration(duration); + if (delay > 0) { + anim.setStartDelay(delay); + } anim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { mCallback.onChildDismissed(view); + if (endAction != null) { + endAction.run(); + } animView.setLayerType(View.LAYER_TYPE_NONE, null); } }); @@ -426,4 +468,15 @@ public class SwipeHelper implements Gefingerpoken { */ boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress); } + + /** + * Equivalent to View.OnLongClickListener with coordinates + */ + public interface LongPressListener { + /** + * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates + * @return whether the longpress was handled + */ + boolean onLongPress(View v, int x, int y); + } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index 333b8b483142..13c15f513853 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -32,7 +32,6 @@ import android.os.Handler; import android.os.PowerManager; import android.os.SystemProperties; import android.os.Vibrator; -import android.service.dreams.DozeHardware; import android.service.dreams.DreamService; import android.util.Log; import android.util.MathUtils; @@ -55,7 +54,6 @@ public class DozeService extends DreamService { private final Handler mHandler = new Handler(); private Host mHost; - private DozeHardware mDozeHardware; private SensorManager mSensors; private Sensor mSigMotionSensor; private PowerManager mPowerManager; @@ -77,7 +75,6 @@ public class DozeService extends DreamService { protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) { super.dumpOnHandler(fd, pw, args); pw.print(" mDreaming: "); pw.println(mDreaming); - pw.print(" mDozeHardware: "); pw.println(mDozeHardware); pw.print(" mTeaseReceiverRegistered: "); pw.println(mTeaseReceiverRegistered); pw.print(" mSigMotionSensor: "); pw.println(mSigMotionSensor); pw.print(" mSigMotionConfigured: "); pw.println(mSigMotionConfigured); @@ -123,9 +120,7 @@ public class DozeService extends DreamService { @Override public void onDreamingStarted() { super.onDreamingStarted(); - mDozeHardware = getDozeHardware(); - if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze() - + " dozeHardware=" + mDozeHardware); + if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze()); mDreaming = true; listenForTeaseSignals(true); requestDoze(); @@ -162,7 +157,6 @@ public class DozeService extends DreamService { super.onDreamingStopped(); mDreaming = false; - mDozeHardware = null; if (mWakeLock.isHeld()) { mWakeLock.release(); } @@ -292,6 +286,11 @@ public class DozeService extends DreamService { @Override public void onNewNotifications() { if (DEBUG) Log.d(mTag, "onNewNotifications"); + // noop for now + } + @Override + public void onBuzzBeepBlinked() { + if (DEBUG) Log.d(mTag, "onBuzzBeepBlinked"); requestTease(); } }; @@ -305,6 +304,7 @@ public class DozeService extends DreamService { public interface Callback { void onNewNotifications(); + void onBuzzBeepBlinked(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index d76a2fedca10..42da282ba81a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -93,10 +93,10 @@ public class CellularTile extends QSTile<QSTile.SignalState> { final Resources r = mContext.getResources(); state.iconId = cb.noSim ? R.drawable.stat_sys_no_sim - : cb.enabled && (cb.mobileSignalIconId > 0) + : cb.enabled && (cb.mobileSignalIconId > 0) && !cb.airplaneModeEnabled ? cb.mobileSignalIconId : R.drawable.ic_qs_signal_no_signal; - state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled + state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiConnected ? cb.dataTypeIconId : 0; state.filter = state.iconId != R.drawable.stat_sys_no_sim; @@ -132,6 +132,8 @@ public class CellularTile extends QSTile<QSTile.SignalState> { private static final class CallbackInfo { boolean enabled; boolean wifiEnabled; + boolean wifiConnected; + boolean airplaneModeEnabled; int mobileSignalIconId; String signalContentDescription; int dataTypeIconId; @@ -144,12 +146,15 @@ public class CellularTile extends QSTile<QSTile.SignalState> { private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() { private boolean mWifiEnabled; + private boolean mWifiConnected; + private boolean mAirplaneModeEnabled; @Override - public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, + public void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId, boolean activityIn, boolean activityOut, String wifiSignalContentDescriptionId, String description) { mWifiEnabled = enabled; + mWifiConnected = connected; } @Override @@ -161,6 +166,8 @@ public class CellularTile extends QSTile<QSTile.SignalState> { final CallbackInfo info = new CallbackInfo(); // TODO pool? info.enabled = enabled; info.wifiEnabled = mWifiEnabled; + info.wifiConnected = mWifiConnected; + info.airplaneModeEnabled = mAirplaneModeEnabled; info.mobileSignalIconId = mobileSignalIconId; info.signalContentDescription = mobileSignalContentDescriptionId; info.dataTypeIconId = dataTypeIconId; @@ -174,7 +181,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> { @Override public void onAirplaneModeChanged(boolean enabled) { - // noop + mAirplaneModeEnabled = enabled; } public void onMobileDataEnabled(boolean enabled) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 35dfddaef6b3..e0b465ed009c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -24,7 +24,6 @@ import android.content.SharedPreferences; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.HotspotController; -import com.android.systemui.statusbar.policy.KeyguardMonitor; /** Quick settings tile: Hotspot **/ public class HotspotTile extends QSTile<QSTile.BooleanState> { @@ -32,14 +31,12 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { private static final long MILLIS_PER_DAY = 1000 * 60 * 60 * 24; private final HotspotController mController; - private final KeyguardMonitor mKeyguard; private final Callback mCallback = new Callback(); private final long mTimeToShowTile; public HotspotTile(Host host) { super(host); mController = host.getHotspotController(); - mKeyguard = host.getKeyguardMonitor(); mTimeToShowTile = MILLIS_PER_DAY * mContext.getResources().getInteger(R.integer.days_to_show_hotspot); @@ -54,10 +51,8 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { public void setListening(boolean listening) { if (listening) { mController.addCallback(mCallback); - mKeyguard.addCallback(mCallback); } else { mController.removeCallback(mCallback); - mKeyguard.removeCallback(mCallback); } } @@ -69,8 +64,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { @Override protected void handleUpdateState(BooleanState state, Object arg) { - state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing()) - && mController.isHotspotSupported() && isHotspotRecentlyUsed(); + state.visible = mController.isHotspotSupported() && isHotspotRecentlyUsed(); state.label = mContext.getString(R.string.quick_settings_hotspot_label); state.value = mController.isHotspotEnabled(); @@ -87,16 +81,11 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { return context.getSharedPreferences(context.getPackageName(), 0); } - private final class Callback implements HotspotController.Callback, KeyguardMonitor.Callback { + private final class Callback implements HotspotController.Callback { @Override public void onHotspotChanged(boolean enabled) { refreshState(); } - - @Override - public void onKeyguardChanged() { - refreshState(); - } }; /** 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 900c7b26b097..1707b320f0b5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -143,6 +143,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> { private static final class CallbackInfo { boolean enabled; + boolean connected; int wifiSignalIconId; String enabledDesc; boolean activityIn; @@ -153,6 +154,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> { public String toString() { return new StringBuilder("CallbackInfo[") .append("enabled=").append(enabled) + .append(",connected=").append(connected) .append(",wifiSignalIconId=").append(wifiSignalIconId) .append(",enabledDesc=").append(enabledDesc) .append(",activityIn=").append(activityIn) @@ -164,12 +166,13 @@ public class WifiTile extends QSTile<QSTile.SignalState> { private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() { @Override - public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, + public void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId, boolean activityIn, boolean activityOut, String wifiSignalContentDescriptionId, String description) { if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled); final CallbackInfo info = new CallbackInfo(); info.enabled = enabled; + info.connected = connected; info.wifiSignalIconId = wifiSignalIconId; info.enabledDesc = description; info.activityIn = activityIn; diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java index 72a33410747f..25a62ae819fb 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java @@ -56,9 +56,7 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView public RecentsHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs, 0); - float densityScale = getResources().getDisplayMetrics().density; - float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); - mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop); + mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, context); mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false); mRecycledViews = new HashSet<View>(); } diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java index 1213375c83f4..e8e9d529e246 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java @@ -56,9 +56,7 @@ public class RecentsVerticalScrollView extends ScrollView public RecentsVerticalScrollView(Context context, AttributeSet attrs) { super(context, attrs, 0); - float densityScale = getResources().getDisplayMetrics().density; - float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); - mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); + mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context); mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true); mRecycledViews = new HashSet<View>(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 591149c8ac22..cbcacc4935f9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -133,7 +133,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta intent.setPackage(mContext.getPackageName()); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(RecentsActivity.EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab); - mContext.sendBroadcast(intent); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); } } } @@ -222,7 +222,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta Intent intent = new Intent(RecentsActivity.ACTION_TOGGLE_RECENTS_ACTIVITY); intent.setPackage(mContext.getPackageName()); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcast(intent); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); mLastToggleTime = System.currentTimeMillis(); return; } else { @@ -444,7 +444,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta Intent intent = new Intent(RecentsActivity.ACTION_START_ENTER_ANIMATION); intent.setPackage(mContext.getPackageName()); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcast(intent); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); mStartAnimationTriggered = true; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java index fd636edcd1b2..dc8f0db33389 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java @@ -163,6 +163,7 @@ class TaskBarView extends FrameLayout { } else if (t.applicationIcon != null) { mApplicationIcon.setImageDrawable(t.applicationIcon); } + mApplicationIcon.setContentDescription(t.activityLabel); if (!mActivityDescription.getText().toString().equals(t.activityLabel)) { mActivityDescription.setText(t.activityLabel); } @@ -176,6 +177,9 @@ class TaskBarView extends FrameLayout { mConfig.taskBarViewLightTextColor : mConfig.taskBarViewDarkTextColor); mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ? mLightDismissDrawable : mDarkDismissDrawable); + mDismissButton.setContentDescription( + getContext().getString(R.string.accessibility_recents_item_will_be_dismissed, + t.activityLabel)); } /** Unbinds the bar view from the task */ 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 32b9d8ab2625..ba90af3516d0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -27,12 +27,12 @@ import android.graphics.Rect; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import android.widget.OverScroller; import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.misc.Console; import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.Utilities; @@ -1006,6 +1006,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void onTaskViewDismissed(TaskView tv) { Task task = tv.getTask(); + // Announce for accessibility + tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed, + tv.getTask().activityLabel)); // Remove the task from the view mStack.removeTask(task); } @@ -1045,4 +1048,4 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java index ad98168e1593..d11313962b53 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java @@ -31,30 +31,14 @@ import android.widget.ImageView; import com.android.systemui.R; /** A dialog that provides controls for adjusting the screen brightness. */ -public class BrightnessDialog extends Activity implements - BrightnessController.BrightnessStateChangeCallback { - private final Handler mHandler = new Handler(); +public class BrightnessDialog extends Activity { private BrightnessController mBrightnessController; - private int mBrightnessDialogLongTimeout; - private int mBrightnessDialogShortTimeout; - - private final Runnable mDismissDialogRunnable = new Runnable() { - public void run() { - finish(); - }; - }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final Resources r = getResources(); - mBrightnessDialogLongTimeout = r.getInteger( - R.integer.quick_settings_brightness_dialog_long_timeout); - mBrightnessDialogShortTimeout = r.getInteger( - R.integer.quick_settings_brightness_dialog_short_timeout); - final Window window = getWindow(); final WindowManager.LayoutParams lp = window.getAttributes(); @@ -79,33 +63,13 @@ public class BrightnessDialog extends Activity implements final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider); mBrightnessController = new BrightnessController(this, icon, slider); mBrightnessController.registerCallbacks(); - mBrightnessController.addStateChangedCallback(this); - - dismissBrightnessDialog(mBrightnessDialogLongTimeout); } @Override protected void onStop() { super.onStop(); - mBrightnessController.removeStateChangedCallback(this); mBrightnessController.unregisterCallbacks(); - - removeAllBrightnessDialogCallbacks(); - } - - public void onBrightnessLevelChanged() { - dismissBrightnessDialog(mBrightnessDialogShortTimeout); - } - - private void dismissBrightnessDialog(int timeout) { - removeAllBrightnessDialogCallbacks(); - - mHandler.postDelayed(mDismissDialogRunnable, timeout); - } - - private void removeAllBrightnessDialogCallbacks() { - mHandler.removeCallbacks(mDismissDialogRunnable); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 0a288d91b4a5..48fc4ec2b824 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.TimeInterpolator; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.Notification; @@ -33,6 +36,7 @@ import android.content.pm.UserInfo; import android.content.res.Configuration; import android.database.ContentObserver; import android.graphics.Rect; +import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; @@ -57,18 +61,17 @@ import android.util.SparseBooleanArray; import android.view.Display; import android.view.IWindowManager; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; +import android.view.ViewAnimationUtils; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; -import android.view.ViewStub; import android.view.WindowManager; import android.view.WindowManagerGlobal; +import android.view.animation.AnimationUtils; import android.widget.DateTimeView; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.PopupMenu; import android.widget.RemoteViews; import android.widget.TextView; @@ -79,6 +82,7 @@ import com.android.internal.util.NotificationColorUtil; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SearchPanelView; +import com.android.systemui.SwipeHelper; import com.android.systemui.SystemUI; import com.android.systemui.statusbar.NotificationData.Entry; import com.android.systemui.statusbar.phone.KeyguardTouchDelegate; @@ -141,8 +145,6 @@ public abstract class BaseStatusBar extends SystemUI implements // Search panel protected SearchPanelView mSearchPanelView; - protected PopupMenu mNotificationBlamePopup; - protected int mCurrentUserId = 0; final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>(); @@ -184,6 +186,11 @@ public abstract class BaseStatusBar extends SystemUI implements protected int mZenMode; + // which notification is currently being longpress-examined by the user + private View mNotificationGutsExposed; + + private TimeInterpolator mLinearOutSlowIn, mFastOutLinearIn; + /** * The {@link StatusBarState} of the status bar. */ @@ -192,6 +199,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected boolean mShowLockscreenNotifications; protected NotificationOverflowContainer mKeyguardIconOverflowContainer; + protected DismissView mDismissView; public boolean isDeviceProvisioned() { return mDeviceProvisioned; @@ -244,9 +252,6 @@ public abstract class BaseStatusBar extends SystemUI implements // the user switches to home. We know it is safe to do at this // point, so make sure new activity switches are now allowed. ActivityManagerNative.getDefault().resumeAppSwitches(); - // Also, notifications can be launched from the lock screen, - // so dismiss the lock screen when the activity starts. - ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); } catch (RemoteException e) { } @@ -418,6 +423,11 @@ public abstract class BaseStatusBar extends SystemUI implements mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.linear_out_slow_in); + mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.fast_out_linear_in); + // Connect in to the status bar manager service StatusBarIconList iconList = new StatusBarIconList(); mCommandQueue = new CommandQueue(this, iconList); @@ -595,29 +605,61 @@ public abstract class BaseStatusBar extends SystemUI implements null, UserHandle.CURRENT); } - protected View.OnLongClickListener getNotificationLongClicker() { - return new View.OnLongClickListener() { + private static final int max(int...args) { + switch (args.length) { + case 0: + return 0; + case 1: + return args[0]; + case 2: + return args[1] > args[0] ? args[1] : args[0]; + default: + int m = args[0]; + for (int i = 0; i < args.length; i++) { + if (args[i] > m) { + m = args[i]; + } + } + return m; + } + } + + protected SwipeHelper.LongPressListener getNotificationLongClicker() { + return new SwipeHelper.LongPressListener() { @Override - public boolean onLongClick(View v) { + public boolean onLongPress(View v, int x, int y) { + dismissPopups(); + final String packageNameF = (String) v.getTag(); if (packageNameF == null) return false; if (v.getWindowToken() == null) return false; - mNotificationBlamePopup = new PopupMenu(mContext, v); - mNotificationBlamePopup.getMenuInflater().inflate( - R.menu.notification_popup_menu, - mNotificationBlamePopup.getMenu()); - mNotificationBlamePopup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - if (item.getItemId() == R.id.notification_inspect_item) { - startApplicationDetailsActivity(packageNameF); - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); - } else { - return false; - } - return true; + + // Assume we are a status_bar_notification_row + final View guts = v.findViewById(R.id.notification_guts); + if (guts == null) return false; + + // Already showing? + if (guts.getVisibility() == View.VISIBLE) return false; + + final View button = guts.findViewById(R.id.notification_inspect_item); + button.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + startApplicationDetailsActivity(packageNameF); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } }); - mNotificationBlamePopup.show(); + + guts.setVisibility(View.VISIBLE); + final double horz = Math.max(v.getWidth() - x, x); + final double vert = Math.max(v.getHeight() - y, y); + final float r = (float) Math.hypot(horz, vert); + final Animator a + = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r); + a.setDuration(400); + a.setInterpolator(mLinearOutSlowIn); + a.start(); + + mNotificationGutsExposed = guts; return true; } @@ -625,9 +667,24 @@ public abstract class BaseStatusBar extends SystemUI implements } public void dismissPopups() { - if (mNotificationBlamePopup != null) { - mNotificationBlamePopup.dismiss(); - mNotificationBlamePopup = null; + if (mNotificationGutsExposed != null) { + final View v = mNotificationGutsExposed; + mNotificationGutsExposed = null; + + final int x = (v.getLeft() + v.getRight()) / 2; + final int y = (v.getTop() + v.getBottom()) / 2; + final Animator a = ViewAnimationUtils.createCircularReveal(v, + x, y, x, 0); + a.setDuration(200); + a.setInterpolator(mFastOutLinearIn); + a.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + v.setVisibility(View.GONE); + } + }); + a.start(); } } @@ -912,6 +969,27 @@ public abstract class BaseStatusBar extends SystemUI implements return inflateViews(entry, parent, true); } + private Drawable loadPackageIconDrawable(String pkg, int userId) { + Drawable icon = null; + try { + icon = mContext.getPackageManager().getApplicationIcon(pkg); + } catch (PackageManager.NameNotFoundException e) { + } + + return icon; + } + + private CharSequence loadPackageName(String pkg) { + final PackageManager pm = mContext.getPackageManager(); + try { + ApplicationInfo info = pm.getApplicationInfo(pkg, + PackageManager.GET_UNINSTALLED_PACKAGES); + if (info != null) return pm.getApplicationLabel(info); + } catch (PackageManager.NameNotFoundException e) { + } + return pkg; + } + private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) { int maxHeight = mRowMaxHeight; StatusBarNotification sbn = entry.notification; @@ -959,8 +1037,15 @@ public abstract class BaseStatusBar extends SystemUI implements parent, false); } - // for blaming (see SwipeHelper.setLongPressListener) + // the notification inspector (see SwipeHelper.setLongPressListener) row.setTag(sbn.getPackageName()); + final View guts = row.findViewById(R.id.notification_guts); + final Drawable pkgicon = loadPackageIconDrawable(entry.notification.getPackageName(), + entry.notification.getUserId()); + final String pkgname = loadPackageName(entry.notification.getPackageName()).toString(); + ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon); + ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(entry.notification.getPostTime()); + ((TextView) row.findViewById(R.id.pkgname)).setText(pkgname); workAroundBadLayerDrawableOpacity(row); View vetoButton = updateNotificationVetoButton(row, sbn); @@ -1012,8 +1097,6 @@ public abstract class BaseStatusBar extends SystemUI implements expanded.setExpandedChild(bigContentViewLocal); } - PackageManager pm = mContext.getPackageManager(); - // now the public version View publicViewLocal = null; if (publicNotification != null) { @@ -1034,6 +1117,9 @@ public abstract class BaseStatusBar extends SystemUI implements } if (publicViewLocal == null) { + PackageManager pm = getPackageManagerForUser( + entry.notification.getUser().getIdentifier()); + // Add a basic notification template publicViewLocal = LayoutInflater.from(mContext).inflate( com.android.internal.R.layout.notification_template_material_base, @@ -1153,9 +1239,6 @@ public abstract class BaseStatusBar extends SystemUI implements // the user switches to home. We know it is safe to do at this // point, so make sure new activity switches are now allowed. ActivityManagerNative.getDefault().resumeAppSwitches(); - // Also, notifications can be launched from the lock screen, - // so dismiss the lock screen when the activity starts. - ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); } catch (RemoteException e) { } @@ -1206,6 +1289,9 @@ public abstract class BaseStatusBar extends SystemUI implements protected void visibilityChanged(boolean visible) { if (mPanelSlightlyVisible != visible) { mPanelSlightlyVisible = visible; + if (!visible) { + dismissPopups(); + } try { if (visible) { mBarService.onPanelRevealed(); @@ -1335,9 +1421,12 @@ public abstract class BaseStatusBar extends SystemUI implements } else { mKeyguardIconOverflowContainer.setVisibility(View.GONE); } - // Move overflow container to last position. + // Move overflow container to second last position. mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer, - mStackScroller.getChildCount() - 1); + mStackScroller.getChildCount() - 2); + + // Now move dismissView to the last position. + mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1); } private boolean shouldShowOnKeyguard(StatusBarNotification sbn) { @@ -1670,4 +1759,26 @@ public abstract class BaseStatusBar extends SystemUI implements // Ignore. } } + + /** + * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then + * return PackageManager for mContext + */ + protected PackageManager getPackageManagerForUser(int userId) { + Context contextForUser = mContext; + // UserHandle defines special userId as negative values, e.g. USER_ALL + if (userId >= 0) { + try { + // Create a context for the correct user so if a package isn't installed + // for user 0 we can still load information about the package. + contextForUser = + mContext.createPackageContextAsUser(mContext.getPackageName(), + Context.CONTEXT_RESTRICTED, + new UserHandle(userId)); + } catch (NameNotFoundException e) { + // Shouldn't fail to find the package name for system ui. + } + } + return contextForUser.getPackageManager(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index eb440028b4b9..a82c9078bc2a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -54,6 +54,7 @@ public class CommandQueue extends IStatusBar.Stub { private static final int MSG_SET_WINDOW_STATE = 13 << MSG_SHIFT; private static final int MSG_SHOW_RECENT_APPS = 14 << MSG_SHIFT; private static final int MSG_HIDE_RECENT_APPS = 15 << MSG_SHIFT; + private static final int MSG_BUZZ_BEEP_BLINKED = 16 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -93,6 +94,7 @@ public class CommandQueue extends IStatusBar.Stub { public void showSearchPanel(); public void hideSearchPanel(); public void setWindowState(int window, int state); + public void buzzBeepBlinked(); } public CommandQueue(Callbacks callbacks, StatusBarIconList list) { @@ -221,6 +223,12 @@ public class CommandQueue extends IStatusBar.Stub { } } + public void buzzBeepBlinked() { + synchronized (mList) { + mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED); + mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED); + } + } private final class H extends Handler { public void handleMessage(Message msg) { @@ -295,6 +303,9 @@ public class CommandQueue extends IStatusBar.Stub { case MSG_SET_WINDOW_STATE: mCallbacks.setWindowState(msg.arg1, msg.arg2); break; + case MSG_BUZZ_BEEP_BLINKED: + mCallbacks.buzzBeepBlinked(); + break; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java new file mode 100644 index 000000000000..d60c17f7caf3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java @@ -0,0 +1,153 @@ +/* + * 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.systemui.statusbar; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator; +import android.widget.Button; +import android.widget.TextView; +import com.android.systemui.R; + +public class DismissView extends ExpandableView { + + private Button mClearAllText; + private boolean mIsVisible; + private boolean mAnimating; + private boolean mWillBeGone; + + private final Interpolator mAppearInterpolator = new PathInterpolator(0f, 0.2f, 1f, 1f); + private final Interpolator mDisappearInterpolator = new PathInterpolator(0f, 0f, 0.8f, 1f); + + public DismissView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mClearAllText = (Button) findViewById(R.id.dismiss_text); + setInvisible(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + setOutlineProvider(null); + } + + @Override + public boolean isTransparent() { + return true; + } + + public void performVisibilityAnimation(boolean nowVisible) { + animateText(nowVisible, null /* onFinishedRunnable */); + } + + public void performVisibilityAnimation(boolean nowVisible, Runnable onFinishedRunnable) { + animateText(nowVisible, onFinishedRunnable); + } + + public boolean isVisible() { + return mIsVisible || mAnimating; + } + + /** + * Animate the text to a new visibility. + * + * @param nowVisible should it now be visible + * @param onFinishedRunnable A runnable which should be run when the animation is + * finished. + */ + private void animateText(boolean nowVisible, final Runnable onFinishedRunnable) { + if (nowVisible != mIsVisible) { + // Animate text + float endValue = nowVisible ? 1.0f : 0.0f; + Interpolator interpolator; + if (nowVisible) { + interpolator = mAppearInterpolator; + } else { + interpolator = mDisappearInterpolator; + } + mAnimating = true; + mClearAllText.animate() + .alpha(endValue) + .setInterpolator(interpolator) + .setDuration(260) + .withLayer() + .withEndAction(new Runnable() { + @Override + public void run() { + mAnimating = false; + if (onFinishedRunnable != null) { + onFinishedRunnable.run(); + } + } + }); + mIsVisible = nowVisible; + } else { + if (onFinishedRunnable != null) { + onFinishedRunnable.run(); + } + } + } + + public void setInvisible() { + mClearAllText.setAlpha(0.0f); + mIsVisible = false; + } + + @Override + public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) { + performVisibilityAnimation(false); + } + + @Override + public void performAddAnimation(long delay) { + performVisibilityAnimation(true); + } + + @Override + public void setScrimAmount(float scrimAmount) { + // We don't need to scrim the dismissView + } + + public void setOnButtonClickListener(OnClickListener onClickListener) { + mClearAllText.setOnClickListener(onClickListener); + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } + + public void cancelAnimation() { + mClearAllText.animate().cancel(); + } + + public boolean willBeGone() { + return mWillBeGone; + } + + public void setWillBeGone(boolean willBeGone) { + mWillBeGone = willBeGone; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index 517a4e84329e..e9989ab2dcdd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; import android.view.MotionEvent; import android.view.View; @@ -46,22 +47,23 @@ public class DragDownHelper implements Gefingerpoken { private float mInitialTouchY; private boolean mDraggingDown; private float mTouchSlop; - private OnDragDownListener mOnDragDownListener; + private DragDownCallback mDragDownCallback; private View mHost; private final int[] mTemp2 = new int[2]; private boolean mDraggedFarEnough; private ExpandableView mStartingChild; private Interpolator mInterpolator; + private float mLastHeight; public DragDownHelper(Context context, View host, ExpandHelper.Callback callback, - OnDragDownListener onDragDownListener) { + DragDownCallback dragDownCallback) { mMinDragDistance = context.getResources().getDimensionPixelSize( R.dimen.keyguard_drag_down_min_distance); mInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mCallback = callback; - mOnDragDownListener = onDragDownListener; + mDragDownCallback = dragDownCallback; mHost = host; } @@ -86,7 +88,7 @@ public class DragDownHelper implements Gefingerpoken { captureStartingChild(mInitialTouchX, mInitialTouchY); mInitialTouchY = y; mInitialTouchX = x; - mOnDragDownListener.onTouchSlopExceeded(); + mDragDownCallback.onTouchSlopExceeded(); return true; } break; @@ -104,29 +106,32 @@ public class DragDownHelper implements Gefingerpoken { switch (event.getActionMasked()) { case MotionEvent.ACTION_MOVE: - final float h = y - mInitialTouchY; + mLastHeight = y - mInitialTouchY; captureStartingChild(mInitialTouchX, mInitialTouchY); if (mStartingChild != null) { - handleExpansion(h, mStartingChild); + handleExpansion(mLastHeight, mStartingChild); + } else { + mDragDownCallback.setEmptyDragAmount(mLastHeight); } - if (h > mMinDragDistance) { + if (mLastHeight > mMinDragDistance) { if (!mDraggedFarEnough) { mDraggedFarEnough = true; - mOnDragDownListener.onThresholdReached(); + mDragDownCallback.onThresholdReached(); } } else { if (mDraggedFarEnough) { mDraggedFarEnough = false; - mOnDragDownListener.onDragDownReset(); + mDragDownCallback.onDragDownReset(); } } return true; case MotionEvent.ACTION_UP: - if (mDraggedFarEnough) { + if (mDraggedFarEnough && mDragDownCallback.onDraggedDown(mStartingChild)) { if (mStartingChild != null) { mCallback.setUserLockedChild(mStartingChild, false); + } else { + mDragDownCallback.setEmptyDragAmount(0f); } - mOnDragDownListener.onDraggedDown(mStartingChild); mDraggingDown = false; } else { stopDragging(); @@ -183,12 +188,27 @@ public class DragDownHelper implements Gefingerpoken { anim.start(); } + private void cancelExpansion() { + ValueAnimator anim = ValueAnimator.ofFloat(mLastHeight, 0); + anim.setInterpolator(mInterpolator); + anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS); + anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mDragDownCallback.setEmptyDragAmount((Float) animation.getAnimatedValue()); + } + }); + anim.start(); + } + private void stopDragging() { if (mStartingChild != null) { cancelExpansion(mStartingChild); + } else { + cancelExpansion(); } mDraggingDown = false; - mOnDragDownListener.onDragDownReset(); + mDragDownCallback.onDragDownReset(); } private ExpandableView findView(float x, float y) { @@ -198,10 +218,15 @@ public class DragDownHelper implements Gefingerpoken { return mCallback.getChildAtRawPosition(x, y); } - public interface OnDragDownListener { - void onDraggedDown(View startingChild); + public interface DragDownCallback { + + /** + * @return true if the interaction is accepted, false if it should be cancelled + */ + boolean onDraggedDown(View startingChild); void onDragDownReset(); void onThresholdReached(); void onTouchSlopExceeded(); + void setEmptyDragAmount(float amount); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java index 9968bbc2f902..9f0f84eb0baf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar; +import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import android.view.ViewPropertyAnimator; @@ -72,7 +73,7 @@ public class FlingAnimationUtils { * @param endValue the end value of the animator * @param velocity the current velocity of the motion */ - public void apply(ValueAnimator animator, float currValue, float endValue, float velocity) { + public void apply(Animator animator, float currValue, float endValue, float velocity) { apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue)); } @@ -101,7 +102,7 @@ public class FlingAnimationUtils { * @param maxDistance the maximum distance for this interaction; the maximum animation length * gets multiplied by the ratio between the actual distance and this value */ - public void apply(ValueAnimator animator, float currValue, float endValue, float velocity, + public void apply(Animator animator, float currValue, float endValue, float velocity, float maxDistance) { AnimatorProperties properties = getProperties(currValue, endValue, velocity, maxDistance); @@ -168,7 +169,7 @@ public class FlingAnimationUtils { * @param maxDistance the maximum distance for this interaction; the maximum animation length * gets multiplied by the ratio between the actual distance and this value */ - public void applyDismissing(ValueAnimator animator, float currValue, float endValue, + public void applyDismissing(Animator animator, float currValue, float endValue, float velocity, float maxDistance) { AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity, maxDistance); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java new file mode 100644 index 000000000000..19bf12147850 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java @@ -0,0 +1,485 @@ +/* + * 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.systemui.statusbar; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ArgbEvaluator; +import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import android.widget.ImageView; +import com.android.systemui.R; + +/** + * An ImageView which does not have overlapping renderings commands and therefore does not need a + * layer when alpha is changed. + */ +public class KeyguardAffordanceView extends ImageView { + + private static final long CIRCLE_APPEAR_DURATION = 80; + private static final long CIRCLE_DISAPPEAR_MAX_DURATION = 200; + private static final long NORMAL_ANIMATION_DURATION = 200; + public static final float MAX_ICON_SCALE_AMOUNT = 1.5f; + public static final float MIN_ICON_SCALE_AMOUNT = 0.8f; + + private final int mMinBackgroundRadius; + private final Paint mCirclePaint; + private final Interpolator mAppearInterpolator; + private final Interpolator mDisappearInterpolator; + private final int mInverseColor; + private final int mNormalColor; + private final ArgbEvaluator mColorInterpolator; + private final FlingAnimationUtils mFlingAnimationUtils; + private final Drawable mArrowDrawable; + private final int mHintChevronPadding; + private float mCircleRadius; + private int mCenterX; + private int mCenterY; + private ValueAnimator mCircleAnimator; + private ValueAnimator mAlphaAnimator; + private ValueAnimator mScaleAnimator; + private ValueAnimator mArrowAnimator; + private float mCircleStartValue; + private boolean mCircleWillBeHidden; + private int[] mTempPoint = new int[2]; + private float mImageScale; + private int mCircleColor; + private boolean mIsLeft; + private float mArrowAlpha = 0.0f; + private View mPreviewView; + private float mCircleStartRadius; + private float mMaxCircleSize; + private Animator mPreviewClipper; + private AnimatorListenerAdapter mClipEndListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mPreviewClipper = null; + } + }; + private AnimatorListenerAdapter mCircleEndListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCircleAnimator = null; + } + }; + private AnimatorListenerAdapter mScaleEndListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mScaleAnimator = null; + } + }; + private AnimatorListenerAdapter mAlphaEndListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mAlphaAnimator = null; + } + }; + private AnimatorListenerAdapter mArrowEndListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mArrowAnimator = null; + } + }; + + public KeyguardAffordanceView(Context context) { + this(context, null); + } + + public KeyguardAffordanceView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public KeyguardAffordanceView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public KeyguardAffordanceView(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + mCirclePaint = new Paint(); + mCirclePaint.setAntiAlias(true); + mCircleColor = 0xffffffff; + mCirclePaint.setColor(mCircleColor); + + mNormalColor = 0xffffffff; + mInverseColor = 0xff000000; + mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize( + R.dimen.keyguard_affordance_min_background_radius); + mHintChevronPadding = mContext.getResources().getDimensionPixelSize( + R.dimen.hint_chevron_circle_padding); + mAppearInterpolator = AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.linear_out_slow_in); + mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.fast_out_linear_in); + mColorInterpolator = new ArgbEvaluator(); + mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f); + mArrowDrawable = context.getDrawable(R.drawable.ic_chevron_left); + mArrowDrawable.setBounds(0, 0, mArrowDrawable.getIntrinsicWidth(), + mArrowDrawable.getIntrinsicHeight()); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + mCenterX = getWidth() / 2; + mCenterY = getHeight() / 2; + mMaxCircleSize = getMaxCircleSize(); + } + + @Override + protected void onDraw(Canvas canvas) { + drawBackgroundCircle(canvas); + drawArrow(canvas); + canvas.save(); + updateIconColor(); + canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2); + super.onDraw(canvas); + canvas.restore(); + } + + public void setPreviewView(View v) { + mPreviewView = v; + } + + private void drawArrow(Canvas canvas) { + if (mArrowAlpha > 0) { + canvas.save(); + canvas.translate(mCenterX, mCenterY); + if (mIsLeft) { + canvas.scale(-1.0f, 1.0f); + } + canvas.translate(- mCircleRadius - mHintChevronPadding + - mArrowDrawable.getIntrinsicWidth() / 2, + - mArrowDrawable.getIntrinsicHeight() / 2); + mArrowDrawable.setAlpha((int) (mArrowAlpha * 255)); + mArrowDrawable.draw(canvas); + canvas.restore(); + } + } + + private void updateIconColor() { + Drawable drawable = getDrawable().mutate(); + float alpha = mCircleRadius / mMinBackgroundRadius; + alpha = Math.min(1.0f, alpha); + int color = (int) mColorInterpolator.evaluate(alpha, mNormalColor, mInverseColor); + drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); + } + + private void drawBackgroundCircle(Canvas canvas) { + if (mCircleRadius > 0) { + updateCircleColor(); + canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mCirclePaint); + } + } + + private void updateCircleColor() { + float fraction = 0.5f + 0.5f * Math.max(0.0f, Math.min(1.0f, + (mCircleRadius - mMinBackgroundRadius) / (0.5f * mMinBackgroundRadius))); + if (mPreviewView != null) { + float finishingFraction = 1 - Math.max(0, mCircleRadius - mCircleStartRadius) + / (mMaxCircleSize - mCircleStartRadius); + fraction *= finishingFraction; + } + int color = Color.argb((int) (Color.alpha(mCircleColor) * fraction), + Color.red(mCircleColor), + Color.green(mCircleColor), Color.blue(mCircleColor)); + mCirclePaint.setColor(color); + } + + public void finishAnimation(float velocity, final Runnable mAnimationEndRunnable) { + cancelAnimator(mCircleAnimator); + cancelAnimator(mPreviewClipper); + mCircleStartRadius = mCircleRadius; + float maxCircleSize = getMaxCircleSize(); + ValueAnimator animatorToRadius = getAnimatorToRadius(maxCircleSize); + mFlingAnimationUtils.applyDismissing(animatorToRadius, mCircleRadius, maxCircleSize, + velocity, maxCircleSize); + animatorToRadius.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mAnimationEndRunnable.run(); + } + }); + animatorToRadius.start(); + setImageAlpha(0, true); + if (mPreviewView != null) { + mPreviewView.setVisibility(View.VISIBLE); + mPreviewClipper = ViewAnimationUtils.createCircularReveal( + mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius, + maxCircleSize); + mFlingAnimationUtils.applyDismissing(mPreviewClipper, mCircleRadius, maxCircleSize, + velocity, maxCircleSize); + mPreviewClipper.addListener(mClipEndListener); + mPreviewClipper.start(); + } + } + + private float getMaxCircleSize() { + getLocationInWindow(mTempPoint); + float rootWidth = getRootView().getWidth(); + float width = mTempPoint[0] + mCenterX; + width = Math.max(rootWidth - width, width); + float height = mTempPoint[1] + mCenterY; + return (float) Math.hypot(width, height); + } + + public void setCircleRadius(float circleRadius) { + setCircleRadius(circleRadius, false); + } + + public void setCircleRadiusWithoutAnimation(float circleRadius) { + cancelAnimator(mCircleAnimator); + setCircleRadius(circleRadius, true); + } + + private void setCircleRadius(float circleRadius, boolean noAnimation) { + + // Check if we need a new animation + boolean radiusHidden = (mCircleAnimator != null && mCircleWillBeHidden) + || (mCircleAnimator == null && mCircleRadius == 0.0f); + boolean nowHidden = circleRadius == 0.0f; + boolean radiusNeedsAnimation = (radiusHidden != nowHidden) && !noAnimation; + if (!radiusNeedsAnimation) { + if (mCircleAnimator == null) { + mCircleRadius = circleRadius; + invalidate(); + if (nowHidden) { + if (mPreviewView != null) { + mPreviewView.setVisibility(View.INVISIBLE); + } + } + } else if (!mCircleWillBeHidden) { + + // We just update the end value + float diff = circleRadius - mMinBackgroundRadius; + PropertyValuesHolder[] values = mCircleAnimator.getValues(); + values[0].setFloatValues(mCircleStartValue + diff, circleRadius); + mCircleAnimator.setCurrentPlayTime(mCircleAnimator.getCurrentPlayTime()); + } + } else { + cancelAnimator(mCircleAnimator); + cancelAnimator(mPreviewClipper); + ValueAnimator animator = getAnimatorToRadius(circleRadius); + Interpolator interpolator = circleRadius == 0.0f + ? mDisappearInterpolator + : mAppearInterpolator; + animator.setInterpolator(interpolator); + float durationFactor = Math.abs(mCircleRadius - circleRadius) + / (float) mMinBackgroundRadius; + long duration = (long) (CIRCLE_APPEAR_DURATION * durationFactor); + duration = Math.min(duration, CIRCLE_DISAPPEAR_MAX_DURATION); + animator.setDuration(duration); + animator.start(); + if (mPreviewView != null) { + mPreviewView.setVisibility(View.VISIBLE); + mPreviewClipper = ViewAnimationUtils.createCircularReveal( + mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius, + circleRadius); + mPreviewClipper.setInterpolator(interpolator); + mPreviewClipper.setDuration(duration); + mPreviewClipper.addListener(mClipEndListener); + mPreviewClipper.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mPreviewView.setVisibility(View.INVISIBLE); + } + }); + mPreviewClipper.start(); + } + } + } + + private ValueAnimator getAnimatorToRadius(float circleRadius) { + ValueAnimator animator = ValueAnimator.ofFloat(mCircleRadius, circleRadius); + mCircleAnimator = animator; + mCircleStartValue = mCircleRadius; + mCircleWillBeHidden = circleRadius == 0.0f; + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mCircleRadius = (float) animation.getAnimatedValue(); + invalidate(); + } + }); + animator.addListener(mCircleEndListener); + return animator; + } + + private void cancelAnimator(Animator animator) { + if (animator != null) { + animator.cancel(); + } + } + + public void setImageScale(float imageScale, boolean animate) { + setImageScale(imageScale, animate, -1, null); + } + + /** + * Sets the scale of the containing image + * + * @param imageScale The new Scale. + * @param animate Should an animation be performed + * @param duration If animate, whats the duration? When -1 we take the default duration + * @param interpolator If animate, whats the interpolator? When null we take the default + * interpolator. + */ + public void setImageScale(float imageScale, boolean animate, long duration, + Interpolator interpolator) { + cancelAnimator(mScaleAnimator); + if (!animate) { + mImageScale = imageScale; + invalidate(); + } else { + ValueAnimator animator = ValueAnimator.ofFloat(mImageScale, imageScale); + mScaleAnimator = animator; + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mImageScale = (float) animation.getAnimatedValue(); + invalidate(); + } + }); + animator.addListener(mScaleEndListener); + if (interpolator == null) { + interpolator = imageScale == 0.0f + ? mDisappearInterpolator + : mAppearInterpolator; + } + animator.setInterpolator(interpolator); + if (duration == -1) { + float durationFactor = Math.abs(mImageScale - imageScale) + / (1.0f - MIN_ICON_SCALE_AMOUNT); + durationFactor = Math.min(1.0f, durationFactor); + duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); + } + animator.setDuration(duration); + animator.start(); + } + } + + public void setImageAlpha(float alpha, boolean animate) { + setImageAlpha(alpha, animate, -1, null, null); + } + + /** + * Sets the alpha of the containing image + * + * @param alpha The new alpha. + * @param animate Should an animation be performed + * @param duration If animate, whats the duration? When -1 we take the default duration + * @param interpolator If animate, whats the interpolator? When null we take the default + * interpolator. + */ + public void setImageAlpha(float alpha, boolean animate, long duration, + Interpolator interpolator, Runnable runnable) { + cancelAnimator(mAlphaAnimator); + int endAlpha = (int) (alpha * 255); + if (!animate) { + setImageAlpha(endAlpha); + } else { + int currentAlpha = getImageAlpha(); + ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha); + mAlphaAnimator = animator; + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + setImageAlpha((int) animation.getAnimatedValue()); + } + }); + animator.addListener(mAlphaEndListener); + if (interpolator == null) { + interpolator = alpha == 0.0f + ? mDisappearInterpolator + : mAppearInterpolator; + } + animator.setInterpolator(interpolator); + if (duration == -1) { + float durationFactor = Math.abs(currentAlpha - endAlpha) / 255f; + durationFactor = Math.min(1.0f, durationFactor); + duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); + } + animator.setDuration(duration); + if (runnable != null) { + animator.addListener(getEndListener(runnable)); + } + animator.start(); + } + } + + private Animator.AnimatorListener getEndListener(final Runnable runnable) { + return new AnimatorListenerAdapter() { + boolean mCancelled; + @Override + public void onAnimationCancel(Animator animation) { + mCancelled = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!mCancelled) { + runnable.run(); + } + } + }; + } + + public float getCircleRadius() { + return mCircleRadius; + } + + public void showArrow(boolean show) { + cancelAnimator(mArrowAnimator); + float targetAlpha = show ? 1.0f : 0.0f; + if (mArrowAlpha == targetAlpha) { + return; + } + ValueAnimator animator = ValueAnimator.ofFloat(mArrowAlpha, targetAlpha); + mArrowAnimator = animator; + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mArrowAlpha = (float) animation.getAnimatedValue(); + invalidate(); + } + }); + animator.addListener(mArrowEndListener); + Interpolator interpolator = show + ? mAppearInterpolator + : mDisappearInterpolator; + animator.setInterpolator(interpolator); + float durationFactor = Math.abs(mArrowAlpha - targetAlpha); + long duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); + animator.setDuration(duration); + animator.start(); + } + + public void setIsLeft(boolean left) { + mIsLeft = left; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java index ce5ab5af7f0e..c75bd2874f5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java @@ -65,13 +65,7 @@ public class NotificationOverflowIconsView extends IconMerger { } private void applyColor(Notification notification, StatusBarIconView view) { - if (notification.color == Notification.COLOR_DEFAULT) { - if (mNotificationColorUtil.isGrayscale(view.getDrawable())) { - view.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY); - } - } else { - view.setColorFilter(notification.color, PorterDuff.Mode.SRC_ATOP); - } + view.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY); } private void updateMoreText() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index f5d4889f1e15..8bae19a0d789 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -167,6 +167,11 @@ public class SignalClusterView apply(); } + @Override + public boolean hasOverlappingRendering() { + return false; + } + private void applyInetProblem(ImageView iv) { iv.setColorFilter(Build.IS_DEBUGGABLE && mInetProblem ? PROBLEM_FILTER : null); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index d5f96195926a..9cc559f7b325 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -21,28 +21,28 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.os.PowerManager; +import android.os.SystemClock; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; -import android.view.ViewPropertyAnimator; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import com.android.systemui.R; import com.android.systemui.statusbar.FlingAnimationUtils; - -import java.util.ArrayList; +import com.android.systemui.statusbar.KeyguardAffordanceView; /** - * A touch handler of the Keyguard which is responsible for swiping the content left or right. + * A touch handler of the keyguard which is responsible for launching phone and camera affordances. */ -public class KeyguardPageSwipeHelper { +public class KeyguardAffordanceHelper { - private static final float SWIPE_MAX_ICON_SCALE_AMOUNT = 2.0f; public static final float SWIPE_RESTING_ALPHA_AMOUNT = 0.5f; - public static final long HINT_PHASE1_DURATION = 250; - private static final long HINT_PHASE2_DURATION = 450; + public static final long HINT_PHASE1_DURATION = 200; + private static final long HINT_PHASE2_DURATION = 350; + private static final float BACKGROUND_RADIUS_SCALE_FACTOR = 0.15f; + private static final int HINT_CIRCLE_OPEN_DURATION = 500; private final Context mContext; @@ -58,24 +58,41 @@ public class KeyguardPageSwipeHelper { private int mTouchSlop; private int mMinTranslationAmount; private int mMinFlingVelocity; - private int mHintDistance; - private final View mLeftIcon; - private final View mCenterIcon; - private final View mRightIcon; - private Interpolator mFastOutSlowIn; - private Interpolator mBounceInterpolator; + private int mHintGrowAmount; + private final KeyguardAffordanceView mLeftIcon; + private final KeyguardAffordanceView mCenterIcon; + private final KeyguardAffordanceView mRightIcon; + private Interpolator mAppearInterpolator; + private Interpolator mDisappearInterpolator; private Animator mSwipeAnimator; - private boolean mCallbackCalled; + private int mMinBackgroundRadius; + private boolean mMotionPerformedByUser; + private AnimatorListenerAdapter mFlingEndListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mSwipeAnimator = null; + setSwipingInProgress(false); + } + }; + private Runnable mAnimationEndRunnable = new Runnable() { + @Override + public void run() { + mCallback.onAnimationToSideEnded(); + } + }; - KeyguardPageSwipeHelper(Callback callback, Context context) { + KeyguardAffordanceHelper(Callback callback, Context context) { mContext = context; mCallback = callback; mLeftIcon = mCallback.getLeftIcon(); + mLeftIcon.setIsLeft(true); mCenterIcon = mCallback.getCenterIcon(); mRightIcon = mCallback.getRightIcon(); - updateIcon(mLeftIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false); - updateIcon(mCenterIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false); - updateIcon(mRightIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false); + mLeftIcon.setPreviewView(mCallback.getLeftPreview()); + mRightIcon.setPreviewView(mCallback.getRightPreview()); + updateIcon(mLeftIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false); + updateIcon(mCenterIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false); + updateIcon(mRightIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false); initDimens(); } @@ -85,12 +102,15 @@ public class KeyguardPageSwipeHelper { mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity(); mMinTranslationAmount = mContext.getResources().getDimensionPixelSize( R.dimen.keyguard_min_swipe_amount); - mHintDistance = - mContext.getResources().getDimensionPixelSize(R.dimen.hint_move_distance_sideways); + mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize( + R.dimen.keyguard_affordance_min_background_radius); + mHintGrowAmount = + mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways); mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f); - mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext, - android.R.interpolator.fast_out_slow_in); - mBounceInterpolator = new BounceInterpolator(); + mAppearInterpolator = AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.linear_out_slow_in); + mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.fast_out_linear_in); } public boolean onTouchEvent(MotionEvent event) { @@ -102,16 +122,18 @@ public class KeyguardPageSwipeHelper { final float y = event.getY(pointerIndex); final float x = event.getX(pointerIndex); + boolean isUp = false; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: if (mSwipingInProgress) { - cancelAnimations(); + cancelAnimation(); } mInitialTouchY = y; mInitialTouchX = x; mTranslationOnDown = mTranslation; initVelocityTracker(); trackMovement(event); + mMotionPerformedByUser = false; break; case MotionEvent.ACTION_POINTER_UP: @@ -135,23 +157,24 @@ public class KeyguardPageSwipeHelper { || (rightSwipePossible() && w < -mTouchSlop)) && Math.abs(w) > Math.abs(y - mInitialTouchY) && !mSwipingInProgress) { - cancelAnimations(); + cancelAnimation(); mInitialTouchY = y; mInitialTouchX = x; mTranslationOnDown = mTranslation; - mSwipingInProgress = true; + setSwipingInProgress(true); } if (mSwipingInProgress) { - setTranslation(mTranslationOnDown + x - mInitialTouchX, false); + setTranslation(mTranslationOnDown + x - mInitialTouchX, false, false); } break; case MotionEvent.ACTION_UP: + isUp = true; case MotionEvent.ACTION_CANCEL: mTrackingPointer = -1; trackMovement(event); if (mSwipingInProgress) { - flingWithCurrentVelocity(); + flingWithCurrentVelocity(!isUp); } if (mVelocityTracker != null) { mVelocityTracker.recycle(); @@ -162,6 +185,13 @@ public class KeyguardPageSwipeHelper { return true; } + private void setSwipingInProgress(boolean inProgress) { + mSwipingInProgress = inProgress; + if (inProgress) { + mCallback.onSwipingStarted(); + } + } + private boolean rightSwipePossible() { return mRightIcon.getVisibility() == View.VISIBLE; } @@ -175,22 +205,14 @@ public class KeyguardPageSwipeHelper { } public void startHintAnimation(boolean right, Runnable onFinishedListener) { + startHintAnimationPhase1(right, onFinishedListener); } - /** - * Phase 1: Move everything sidewards. - */ - private void startHintAnimationPhase1(boolean right, final Runnable onFinishedListener) { - float target = right ? -mHintDistance : mHintDistance; - startHintTranslationAnimations(target, HINT_PHASE1_DURATION, mFastOutSlowIn); - ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mTranslation = (float) animation.getAnimatedValue(); - } - }); + private void startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener) { + final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; + targetView.showArrow(true); + ValueAnimator animator = getAnimatorToRadius(right, mHintGrowAmount); animator.addListener(new AnimatorListenerAdapter() { private boolean mCancelled; @@ -204,12 +226,13 @@ public class KeyguardPageSwipeHelper { if (mCancelled) { mSwipeAnimator = null; onFinishedListener.run(); + targetView.showArrow(false); } else { - startUnlockHintAnimationPhase2(onFinishedListener); + startUnlockHintAnimationPhase2(right, onFinishedListener); } } }); - animator.setInterpolator(mFastOutSlowIn); + animator.setInterpolator(mAppearInterpolator); animator.setDuration(HINT_PHASE1_DURATION); animator.start(); mSwipeAnimator = animator; @@ -218,75 +241,69 @@ public class KeyguardPageSwipeHelper { /** * Phase 2: Move back. */ - private void startUnlockHintAnimationPhase2(final Runnable onFinishedListener) { - startHintTranslationAnimations(0f /* target */, HINT_PHASE2_DURATION, mBounceInterpolator); - ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, 0f); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mTranslation = (float) animation.getAnimatedValue(); - } - }); + private void startUnlockHintAnimationPhase2(boolean right, final Runnable onFinishedListener) { + final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; + ValueAnimator animator = getAnimatorToRadius(right, 0); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mSwipeAnimator = null; + targetView.showArrow(false); onFinishedListener.run(); } + + @Override + public void onAnimationStart(Animator animation) { + targetView.showArrow(false); + } }); - animator.setInterpolator(mBounceInterpolator); + animator.setInterpolator(mDisappearInterpolator); animator.setDuration(HINT_PHASE2_DURATION); + animator.setStartDelay(HINT_CIRCLE_OPEN_DURATION); animator.start(); mSwipeAnimator = animator; } - private void startHintTranslationAnimations(float target, long duration, - Interpolator interpolator) { - ArrayList<View> targetViews = mCallback.getTranslationViews(); - for (View targetView : targetViews) { - targetView.animate() - .setDuration(duration) - .setInterpolator(interpolator) - .translationX(target); - } + private ValueAnimator getAnimatorToRadius(final boolean right, int radius) { + final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; + ValueAnimator animator = ValueAnimator.ofFloat(targetView.getCircleRadius(), radius); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float newRadius = (float) animation.getAnimatedValue(); + targetView.setCircleRadiusWithoutAnimation(newRadius); + float translation = getTranslationFromRadius(newRadius); + mTranslation = right ? -translation : translation; + updateIconsFromRadius(targetView, newRadius); + } + }); + return animator; } - private void cancelAnimations() { - ArrayList<View> targetViews = mCallback.getTranslationViews(); - for (View target : targetViews) { - target.animate().cancel(); - } - View targetView = mTranslation > 0 ? mLeftIcon : mRightIcon; - targetView.animate().cancel(); + private void cancelAnimation() { if (mSwipeAnimator != null) { mSwipeAnimator.cancel(); - hideInactiveIcons(true); } } - private void flingWithCurrentVelocity() { + private void flingWithCurrentVelocity(boolean forceSnapBack) { float vel = getCurrentVelocity(); // We snap back if the current translation is not far enough - boolean snapBack = Math.abs(mTranslation) < mMinTranslationAmount; + boolean snapBack = Math.abs(mTranslation) < Math.abs(mTranslationOnDown) + + mMinTranslationAmount; // or if the velocity is in the opposite direction. boolean velIsInWrongDirection = vel * mTranslation < 0; snapBack |= Math.abs(vel) > mMinFlingVelocity && velIsInWrongDirection; vel = snapBack ^ velIsInWrongDirection ? 0 : vel; - fling(vel, snapBack); + fling(vel, snapBack || forceSnapBack); } private void fling(float vel, final boolean snapBack) { float target = mTranslation < 0 ? -mCallback.getPageWidth() : mCallback.getPageWidth(); target = snapBack ? 0 : target; - // translation Animation - startTranslationAnimations(vel, target); - - // animate left / right icon - startIconAnimation(vel, snapBack, target); - ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target); mFlingAnimationUtils.apply(animator, mTranslation, target, vel); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @@ -295,109 +312,78 @@ public class KeyguardPageSwipeHelper { mTranslation = (float) animation.getAnimatedValue(); } }); - animator.addListener(new AnimatorListenerAdapter() { - private boolean mCancelled; - - @Override - public void onAnimationCancel(Animator animation) { - mCancelled = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - mSwipeAnimator = null; - mSwipingInProgress = false; - if (!snapBack && !mCallbackCalled && !mCancelled) { - - // ensure that the callback is called eventually - mCallback.onAnimationToSideStarted(mTranslation < 0); - mCallbackCalled = true; - } - } - }); + animator.addListener(mFlingEndListener); if (!snapBack) { - mCallbackCalled = false; - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - int frameNumber; - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (frameNumber == 2 && !mCallbackCalled) { - - // we have to wait for the second frame for this call, - // until the render thread has definitely kicked in, to avoid a lag. - mCallback.onAnimationToSideStarted(mTranslation < 0); - mCallbackCalled = true; - } - frameNumber++; - } - }); + startFinishingCircleAnimation(vel * 0.375f, mAnimationEndRunnable); + mCallback.onAnimationToSideStarted(mTranslation < 0); } else { - showAllIcons(true); + reset(true); } animator.start(); mSwipeAnimator = animator; } - private void startTranslationAnimations(float vel, float target) { - ArrayList<View> targetViews = mCallback.getTranslationViews(); - for (View targetView : targetViews) { - ViewPropertyAnimator animator = targetView.animate(); - mFlingAnimationUtils.apply(animator, mTranslation, target, vel); - animator.translationX(target); - } + private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable) { + KeyguardAffordanceView targetView = mTranslation > 0 ? mLeftIcon : mRightIcon; + targetView.finishAnimation(velocity, mAnimationEndRunnable); } - private void startIconAnimation(float vel, boolean snapBack, float target) { - float scale = snapBack ? 1.0f : SWIPE_MAX_ICON_SCALE_AMOUNT; - float alpha = snapBack ? SWIPE_RESTING_ALPHA_AMOUNT : 1.0f; - View targetView = mTranslation > 0 - ? mLeftIcon - : mRightIcon; - if (targetView.getVisibility() == View.VISIBLE) { - ViewPropertyAnimator iconAnimator = targetView.animate(); - mFlingAnimationUtils.apply(iconAnimator, mTranslation, target, vel); - iconAnimator.scaleX(scale); - iconAnimator.scaleY(scale); - iconAnimator.alpha(alpha); - } - } - - private void setTranslation(float translation, boolean isReset) { + private void setTranslation(float translation, boolean isReset, boolean animateReset) { translation = rightSwipePossible() ? translation : Math.max(0, translation); translation = leftSwipePossible() ? translation : Math.min(0, translation); + float absTranslation = Math.abs(translation); + if (absTranslation > Math.abs(mTranslationOnDown) + mMinTranslationAmount || + mMotionPerformedByUser) { + mMotionPerformedByUser = true; + } if (translation != mTranslation || isReset) { - ArrayList<View> translatedViews = mCallback.getTranslationViews(); - for (View view : translatedViews) { - view.setTranslationX(translation); - } - if (translation == 0.0f) { - boolean animate = !isReset; - showAllIcons(animate); + KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon; + KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon; + float alpha = absTranslation / mMinTranslationAmount; + + // We interpolate the alpha of the other icons to 0 + float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha); + fadeOutAlpha = Math.max(0.0f, fadeOutAlpha); + + // We interpolate the alpha of the targetView to 1 + alpha = fadeOutAlpha + alpha; + + boolean animateIcons = isReset && animateReset; + float radius = getRadiusFromTranslation(absTranslation); + if (!isReset) { + updateIcon(targetView, radius, alpha, false); } else { - View targetView = translation > 0 ? mLeftIcon : mRightIcon; - float progress = Math.abs(translation) / mCallback.getPageWidth(); - progress = Math.min(progress, 1.0f); - float alpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - progress) + progress; - float scale = (1.0f - progress) + progress * SWIPE_MAX_ICON_SCALE_AMOUNT; - updateIcon(targetView, scale, alpha, false); - View otherView = translation < 0 ? mLeftIcon : mRightIcon; - if (mTranslation * translation <= 0) { - // The sign of the translation has changed so we need to hide the other icons - updateIcon(otherView, 0, 0, true); - updateIcon(mCenterIcon, 0, 0, true); - } + updateIcon(targetView, 0.0f, fadeOutAlpha, animateIcons); } + updateIcon(otherView, 0.0f, fadeOutAlpha, animateIcons); + updateIcon(mCenterIcon, 0.0f, fadeOutAlpha, animateIcons); + mTranslation = translation; } } - public void showAllIcons(boolean animate) { - float scale = 1.0f; - float alpha = SWIPE_RESTING_ALPHA_AMOUNT; - updateIcon(mRightIcon, scale, alpha, animate); - updateIcon(mCenterIcon, scale, alpha, animate); - updateIcon(mLeftIcon, scale, alpha, animate); + private void updateIconsFromRadius(KeyguardAffordanceView targetView, float newRadius) { + float alpha = newRadius / mMinBackgroundRadius; + + // We interpolate the alpha of the other icons to 0 + float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha); + fadeOutAlpha = Math.max(0.0f, fadeOutAlpha); + + // We interpolate the alpha of the targetView to 1 + alpha = fadeOutAlpha + alpha; + KeyguardAffordanceView otherView = targetView == mRightIcon ? mLeftIcon : mRightIcon; + updateIconAlpha(targetView, alpha, false); + updateIconAlpha(otherView, fadeOutAlpha, false); + updateIconAlpha(mCenterIcon, fadeOutAlpha, false); + } + + private float getTranslationFromRadius(float circleSize) { + float translation = (circleSize - mMinBackgroundRadius) / BACKGROUND_RADIUS_SCALE_FACTOR; + return Math.max(0, translation); + } + + private float getRadiusFromTranslation(float translation) { + return translation * BACKGROUND_RADIUS_SCALE_FACTOR + mMinBackgroundRadius; } public void animateHideLeftRightIcon() { @@ -405,32 +391,26 @@ public class KeyguardPageSwipeHelper { updateIcon(mLeftIcon, 0f, 0f, true); } - private void hideInactiveIcons(boolean animate){ - View otherView = mTranslation < 0 ? mLeftIcon : mRightIcon; - updateIcon(otherView, 0, 0, animate); - updateIcon(mCenterIcon, 0, 0, animate); - } - - private void updateIcon(View view, float scale, float alpha, boolean animate) { + private void updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha, + boolean animate) { if (view.getVisibility() != View.VISIBLE) { return; } - if (!animate) { - view.animate().cancel(); - view.setAlpha(alpha); - view.setScaleX(scale); - view.setScaleY(scale); - // TODO: remove this invalidate once the property setters invalidate it properly - view.invalidate(); - } else { - if (view.getAlpha() != alpha || view.getScaleX() != scale) { - view.animate() - .setInterpolator(mFastOutSlowIn) - .alpha(alpha) - .scaleX(scale) - .scaleY(scale); - } - } + view.setCircleRadius(circleRadius); + updateIconAlpha(view, alpha, animate); + } + + private void updateIconAlpha(KeyguardAffordanceView view, float alpha, boolean animate) { + float scale = getScale(alpha); + alpha = Math.min(1.0f, alpha); + view.setImageAlpha(alpha, animate); + view.setImageScale(scale, animate); + } + + private float getScale(float alpha) { + float scale = alpha / SWIPE_RESTING_ALPHA_AMOUNT * 0.2f + + KeyguardAffordanceView.MIN_ICON_SCALE_AMOUNT; + return Math.min(scale, KeyguardAffordanceView.MAX_ICON_SCALE_AMOUNT); } private void trackMovement(MotionEvent event) { @@ -458,20 +438,12 @@ public class KeyguardPageSwipeHelper { initDimens(); } - public void reset() { + public void reset(boolean animate) { if (mSwipeAnimator != null) { mSwipeAnimator.cancel(); } - ArrayList<View> targetViews = mCallback.getTranslationViews(); - for (View view : targetViews) { - view.animate().cancel(); - } - setTranslation(0.0f, true); - mSwipingInProgress = false; - } - - public boolean isSwipingInProgress() { - return mSwipingInProgress; + setTranslation(0.0f, true, animate); + setSwipingInProgress(false); } public interface Callback { @@ -483,14 +455,23 @@ public class KeyguardPageSwipeHelper { */ void onAnimationToSideStarted(boolean rightPage); + /** + * Notifies the callback the animation to a side page has ended. + */ + void onAnimationToSideEnded(); + float getPageWidth(); - ArrayList<View> getTranslationViews(); + void onSwipingStarted(); + + KeyguardAffordanceView getLeftIcon(); + + KeyguardAffordanceView getCenterIcon(); - View getLeftIcon(); + KeyguardAffordanceView getRightIcon(); - View getCenterIcon(); + View getLeftPreview(); - View getRightIcon(); + View getRightPreview(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 74bc6984d137..b5f517d25beb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -30,6 +30,7 @@ import android.provider.MediaStore; import android.util.AttributeSet; import android.util.Log; import android.view.View; +import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import android.widget.ImageView; @@ -39,6 +40,8 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.R; import com.android.systemui.statusbar.policy.FlashlightController; +import com.android.systemui.statusbar.KeyguardAffordanceView; +import com.android.systemui.statusbar.policy.PreviewInflater; /** * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status @@ -56,10 +59,14 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL); - private ImageView mCameraImageView; - private ImageView mPhoneImageView; - private ImageView mLockIcon; + private KeyguardAffordanceView mCameraImageView; + private KeyguardAffordanceView mPhoneImageView; + private KeyguardAffordanceView mLockIcon; private View mIndicationText; + private ViewGroup mPreviewContainer; + + private View mPhonePreview; + private View mCameraPreview; private ActivityStarter mActivityStarter; private UnlockMethodCache mUnlockMethodCache; @@ -87,9 +94,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL protected void onFinishInflate() { super.onFinishInflate(); mLockPatternUtils = new LockPatternUtils(mContext); - mCameraImageView = (ImageView) findViewById(R.id.camera_button); - mPhoneImageView = (ImageView) findViewById(R.id.phone_button); - mLockIcon = (ImageView) findViewById(R.id.lock_icon); + mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container); + mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button); + mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button); + mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon); mIndicationText = findViewById(R.id.keyguard_indication_text); watchForCameraPolicyChanges(); watchForAccessibilityChanges(); @@ -98,6 +106,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mUnlockMethodCache = UnlockMethodCache.getInstance(getContext()); mUnlockMethodCache.addListener(this); updateTrust(); + setClipChildren(false); + setClipToPadding(false); + inflatePreviews(); } public void setActivityStarter(ActivityStarter activityStarter) { @@ -228,15 +239,23 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mLockIcon.setImageResource(iconRes); } - public ImageView getPhoneImageView() { + public KeyguardAffordanceView getPhoneView() { return mPhoneImageView; } - public ImageView getCameraImageView() { + public KeyguardAffordanceView getCameraView() { return mCameraImageView; } - public ImageView getLockIcon() { + public View getPhonePreview() { + return mPhonePreview; + } + + public View getCameraPreview() { + return mCameraPreview; + } + + public KeyguardAffordanceView getLockIcon() { return mLockIcon; } @@ -255,6 +274,20 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateCameraVisibility(); } + private void inflatePreviews() { + PreviewInflater inflater = new PreviewInflater(mContext, new LockPatternUtils(mContext)); + mPhonePreview = inflater.inflatePreview(PHONE_INTENT); + mCameraPreview = inflater.inflatePreview(getCameraIntent()); + if (mPhonePreview != null) { + mPreviewContainer.addView(mPhonePreview); + mPhonePreview.setVisibility(View.INVISIBLE); + } + if (mCameraPreview != null) { + mPreviewContainer.addView(mCameraPreview); + mCameraPreview.setVisibility(View.INVISIBLE); + } + } + private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { post(new Runnable() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 3aaace4ef16a..e6ffde0491a2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -100,7 +100,7 @@ public class KeyguardBouncer { .withLayer() // Make it disappear faster, as the focus should be on the activity behind. - .setDuration(duration / 3) + .setDuration(duration / 2) .setInterpolator(mFadeOutInterpolator) .setStartDelay(delay) .withEndAction(new Runnable() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 319096d197e6..a15d35e5918d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -36,7 +36,6 @@ public class KeyguardClockPositionAlgorithm { private static final float CLOCK_SCALE_FADE_END = 0.75f; private static final float CLOCK_SCALE_FADE_END_NO_NOTIFS = 0.5f; - private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f; private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f; @@ -50,6 +49,8 @@ public class KeyguardClockPositionAlgorithm { private int mNotificationCount; private int mHeight; private int mKeyguardStatusHeight; + private float mEmptyDragAmount; + private float mDensity; /** * The number (fractional) of notifications the "more" card counts when calculating how many @@ -81,16 +82,18 @@ public class KeyguardClockPositionAlgorithm { mMoreCardNotificationAmount = (float) res.getDimensionPixelSize(R.dimen.notification_summary_height) / res.getDimensionPixelSize(R.dimen.notification_min_height); + mDensity = res.getDisplayMetrics().density; } public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight, - int notificationCount, int height, int keyguardStatusHeight) { + int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount) { mMaxKeyguardNotifications = maxKeyguardNotifications; mMaxPanelHeight = maxPanelHeight; mExpandedHeight = expandedHeight; mNotificationCount = notificationCount; mHeight = height; mKeyguardStatusHeight = keyguardStatusHeight; + mEmptyDragAmount = emptyDragAmount; } public void run(Result result) { @@ -116,6 +119,7 @@ public class KeyguardClockPositionAlgorithm { float progress = distanceToScaleEnd / (startPadding - scaleEnd); progress = Math.max(0.0f, Math.min(progress, 1.0f)); progress = mAccelerateInterpolator.getInterpolation(progress); + progress *= Math.pow(1 + mEmptyDragAmount / mDensity / 300, 0.3f); return progress; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java new file mode 100644 index 000000000000..7579039fd7f4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java @@ -0,0 +1,70 @@ +/* + * 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.systemui.statusbar.phone; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.WindowInsets; +import android.widget.FrameLayout; + +/** + * A view group which contains the preview of phone/camera and draws a black bar at the bottom as + * the fake navigation bar. + */ +public class KeyguardPreviewContainer extends FrameLayout { + + private Drawable mBlackBarDrawable = new Drawable() { + @Override + public void draw(Canvas canvas) { + canvas.save(); + canvas.clipRect(0, getHeight() - getPaddingBottom(), getWidth(), getHeight()); + canvas.drawColor(Color.BLACK); + canvas.restore(); + } + + @Override + public void setAlpha(int alpha) { + // noop + } + + @Override + public void setColorFilter(ColorFilter cf) { + // noop + } + + @Override + public int getOpacity() { + return android.graphics.PixelFormat.OPAQUE; + } + }; + + public KeyguardPreviewContainer(Context context, AttributeSet attrs) { + super(context, attrs); + setBackground(mBlackBarDrawable); + } + + @Override + public WindowInsets onApplyWindowInsets(WindowInsets insets) { + setPadding(0, 0, 0, insets.getStableInsetBottom()); + return super.onApplyWindowInsets(insets); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index 688c0d84cfa4..af302662e070 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -26,7 +26,7 @@ import android.view.View; import android.widget.FrameLayout; import com.android.systemui.qs.QSPanel; -import com.android.systemui.qs.tiles.UserDetailView; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; /** * Container for image of the multi user switcher (tappable). @@ -34,6 +34,8 @@ import com.android.systemui.qs.tiles.UserDetailView; public class MultiUserSwitch extends FrameLayout implements View.OnClickListener { private QSPanel mQsPanel; + private KeyguardUserSwitcher mKeyguardUserSwitcher; + private boolean mKeyguardMode; public MultiUserSwitch(Context context, AttributeSet attrs) { super(context, attrs); @@ -49,12 +51,26 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener mQsPanel = qsPanel; } + public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { + mKeyguardUserSwitcher = keyguardUserSwitcher; + } + + public void setKeyguardMode(boolean keyguardShowing) { + mKeyguardMode = keyguardShowing; + } + @Override public void onClick(View v) { final UserManager um = UserManager.get(getContext()); if (um.isUserSwitcherEnabled()) { - mQsPanel.showDetailAdapter(true, - mQsPanel.getHost().getUserSwitcherController().userDetailAdapter); + if (mKeyguardMode) { + if (mKeyguardUserSwitcher != null) { + mKeyguardUserSwitcher.show(); + } + } else { + mQsPanel.showDetailAdapter(true, + mQsPanel.getHost().getUserSwitcherController().userDetailAdapter); + } } else { Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent( getContext(), v, ContactsContract.Profile.CONTENT_URI, 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 fc0f2d56a1b8..b80a33bff5c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -39,17 +39,16 @@ import com.android.systemui.qs.QSPanel; import com.android.systemui.statusbar.ExpandableView; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.GestureRecorder; +import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.MirrorView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.StackStateAnimator; -import java.util.ArrayList; - public class NotificationPanelView extends PanelView implements ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener, View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener, - KeyguardPageSwipeHelper.Callback { + KeyguardAffordanceHelper.Callback { // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is // changed. @@ -59,7 +58,7 @@ public class NotificationPanelView extends PanelView implements private static final float HEADER_RUBBERBAND_FACTOR = 2.15f; private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f; - private KeyguardPageSwipeHelper mPageSwiper; + private KeyguardAffordanceHelper mAfforanceHelper; private StatusBarHeaderView mHeader; private View mQsContainer; private QSPanel mQsPanel; @@ -111,6 +110,7 @@ public class NotificationPanelView extends PanelView implements private boolean mUnlockIconActive; private int mNotificationsHeaderCollideDistance; private int mUnlockMoveDistance; + private float mEmptyDragAmount; private Interpolator mFastOutSlowInInterpolator; private Interpolator mFastOutLinearInterpolator; @@ -124,7 +124,6 @@ public class NotificationPanelView extends PanelView implements private boolean mIsExpanding; private boolean mBlockTouches; - private ArrayList<View> mSwipeTranslationViews = new ArrayList<>(); private int mNotificationScrimWaitDistance; private boolean mTwoFingerQsExpand; private boolean mTwoFingerQsExpandPossible; @@ -135,6 +134,10 @@ public class NotificationPanelView extends PanelView implements */ private int mScrollYOverride = -1; private boolean mQsAnimatorExpand; + private boolean mIsLaunchTransitionFinished; + private boolean mIsLaunchTransitionRunning; + private Runnable mLaunchAnimationEndRunnable; + private boolean mOnlyAffordanceInThisMotion; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -167,9 +170,7 @@ public class NotificationPanelView extends PanelView implements mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(), android.R.interpolator.fast_out_linear_in); mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area); - mSwipeTranslationViews.add(mNotificationStackScroller); - mSwipeTranslationViews.add(mKeyguardStatusView); - mPageSwiper = new KeyguardPageSwipeHelper(this, getContext()); + mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext()); } @Override @@ -234,7 +235,8 @@ public class NotificationPanelView extends PanelView implements getExpandedHeight(), mNotificationStackScroller.getNotGoneChildCount(), getHeight(), - mKeyguardStatusView.getHeight()); + mKeyguardStatusView.getHeight(), + mEmptyDragAmount); mClockPositionAlgorithm.run(mClockPositionResult); if (animate || mClockAnimator != null) { startClockAnimation(mClockPositionResult.clockY); @@ -297,9 +299,10 @@ public class NotificationPanelView extends PanelView implements @Override public void resetViews() { + mIsLaunchTransitionFinished = false; mBlockTouches = false; mUnlockIconActive = false; - mPageSwiper.reset(); + mAfforanceHelper.reset(true); closeQs(); mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */, true /* cancelAnimators */); @@ -354,6 +357,7 @@ public class NotificationPanelView extends PanelView implements if (mBlockTouches) { return false; } + resetDownStates(event); int pointerIndex = event.findPointerIndex(mTrackingPointer); if (pointerIndex < 0) { pointerIndex = 0; @@ -430,6 +434,12 @@ public class NotificationPanelView extends PanelView implements return !mQsExpanded && super.onInterceptTouchEvent(event); } + private void resetDownStates(MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mOnlyAffordanceInThisMotion = false; + } + } + @Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { @@ -464,15 +474,14 @@ public class NotificationPanelView extends PanelView implements if (mBlockTouches) { return false; } - // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference - // implementation. + resetDownStates(event); if ((!mIsExpanding || mHintAnimationRunning) && !mQsExpanded && mStatusBar.getBarState() != StatusBarState.SHADE) { - mPageSwiper.onTouchEvent(event); - if (mPageSwiper.isSwipingInProgress()) { - return true; - } + mAfforanceHelper.onTouchEvent(event); + } + if (mOnlyAffordanceInThisMotion) { + return true; } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f && mStatusBar.getBarState() != StatusBarState.KEYGUARD) { @@ -951,20 +960,16 @@ public class NotificationPanelView extends PanelView implements if (mStatusBar.getBarState() == StatusBarState.KEYGUARD || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) { boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance; + KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon(); if (active && !mUnlockIconActive && mTracking) { - mKeyguardBottomArea.getLockIcon().animate() - .alpha(1f) - .scaleY(LOCK_ICON_ACTIVE_SCALE) - .scaleX(LOCK_ICON_ACTIVE_SCALE) - .setInterpolator(mFastOutLinearInterpolator) - .setDuration(150); + lockIcon.setImageAlpha(1.0f, true, 150, mFastOutLinearInterpolator, null); + lockIcon.setImageScale(LOCK_ICON_ACTIVE_SCALE, true, 150, + mFastOutLinearInterpolator); } else if (!active && mUnlockIconActive && mTracking) { - mKeyguardBottomArea.getLockIcon().animate() - .alpha(KeyguardPageSwipeHelper.SWIPE_RESTING_ALPHA_AMOUNT) - .scaleY(1f) - .scaleX(1f) - .setInterpolator(mFastOutLinearInterpolator) - .setDuration(150); + lockIcon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT, true, + 150, mFastOutLinearInterpolator, null); + lockIcon.setImageScale(1.0f, true, 150, + mFastOutLinearInterpolator); } mUnlockIconActive = active; } @@ -1093,7 +1098,7 @@ public class NotificationPanelView extends PanelView implements super.onTrackingStarted(); if (mStatusBar.getBarState() == StatusBarState.KEYGUARD || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) { - mPageSwiper.animateHideLeftRightIcon(); + mAfforanceHelper.animateHideLeftRightIcon(); } } @@ -1106,16 +1111,15 @@ public class NotificationPanelView extends PanelView implements } if (expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) { - mPageSwiper.showAllIcons(true); + if (!mHintAnimationRunning) { + mAfforanceHelper.reset(true); + } } if (!expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) { - mKeyguardBottomArea.getLockIcon().animate() - .alpha(0f) - .scaleX(2f) - .scaleY(2f) - .setInterpolator(mFastOutLinearInterpolator) - .setDuration(100); + KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon(); + lockIcon.setImageAlpha(0.0f, true, 100, mFastOutLinearInterpolator, null); + lockIcon.setImageScale(2.0f, true, 100, mFastOutLinearInterpolator); } } @@ -1141,7 +1145,7 @@ public class NotificationPanelView extends PanelView implements @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - mPageSwiper.onConfigurationChanged(); + mAfforanceHelper.onConfigurationChanged(); } @Override @@ -1159,6 +1163,8 @@ public class NotificationPanelView extends PanelView implements @Override public void onAnimationToSideStarted(boolean rightPage) { boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? rightPage : !rightPage; + mIsLaunchTransitionRunning = true; + mLaunchAnimationEndRunnable = null; if (start) { mKeyguardBottomArea.launchPhone(); } else { @@ -1168,20 +1174,29 @@ public class NotificationPanelView extends PanelView implements } @Override + public void onAnimationToSideEnded() { + mIsLaunchTransitionRunning = false; + mIsLaunchTransitionFinished = true; + if (mLaunchAnimationEndRunnable != null) { + mLaunchAnimationEndRunnable.run(); + mLaunchAnimationEndRunnable = null; + } + } + + @Override protected void onEdgeClicked(boolean right) { if ((right && getRightIcon().getVisibility() != View.VISIBLE) || (!right && getLeftIcon().getVisibility() != View.VISIBLE)) { return; } mHintAnimationRunning = true; - mPageSwiper.startHintAnimation(right, new Runnable() { + mAfforanceHelper.startHintAnimation(right, new Runnable() { @Override public void run() { mHintAnimationRunning = false; mStatusBar.onHintFinished(); } }); - startHighlightIconAnimation(right ? getRightIcon() : getLeftIcon()); boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? right : !right; if (start) { mStatusBar.onPhoneHintStarted(); @@ -1199,17 +1214,14 @@ public class NotificationPanelView extends PanelView implements /** * Starts the highlight (making it fully opaque) animation on an icon. */ - private void startHighlightIconAnimation(final View icon) { - icon.animate() - .alpha(1.0f) - .setDuration(KeyguardPageSwipeHelper.HINT_PHASE1_DURATION) - .setInterpolator(mFastOutSlowInInterpolator) - .withEndAction(new Runnable() { + private void startHighlightIconAnimation(final KeyguardAffordanceView icon) { + icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION, + mFastOutSlowInInterpolator, new Runnable() { @Override public void run() { - icon.animate().alpha(KeyguardPageSwipeHelper.SWIPE_RESTING_ALPHA_AMOUNT) - .setDuration(KeyguardPageSwipeHelper.HINT_PHASE1_DURATION) - .setInterpolator(mFastOutSlowInInterpolator); + icon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT, + true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION, + mFastOutSlowInInterpolator, null); } }); } @@ -1220,27 +1232,42 @@ public class NotificationPanelView extends PanelView implements } @Override - public ArrayList<View> getTranslationViews() { - return mSwipeTranslationViews; + public void onSwipingStarted() { + requestDisallowInterceptTouchEvent(true); + mOnlyAffordanceInThisMotion = true; } @Override - public View getLeftIcon() { + public KeyguardAffordanceView getLeftIcon() { return getLayoutDirection() == LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getCameraImageView() - : mKeyguardBottomArea.getPhoneImageView(); + ? mKeyguardBottomArea.getCameraView() + : mKeyguardBottomArea.getPhoneView(); } @Override - public View getCenterIcon() { + public KeyguardAffordanceView getCenterIcon() { return mKeyguardBottomArea.getLockIcon(); } @Override - public View getRightIcon() { + public KeyguardAffordanceView getRightIcon() { + return getLayoutDirection() == LAYOUT_DIRECTION_RTL + ? mKeyguardBottomArea.getPhoneView() + : mKeyguardBottomArea.getCameraView(); + } + + @Override + public View getLeftPreview() { + return getLayoutDirection() == LAYOUT_DIRECTION_RTL + ? mKeyguardBottomArea.getCameraPreview() + : mKeyguardBottomArea.getPhonePreview(); + } + + @Override + public View getRightPreview() { return getLayoutDirection() == LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getPhoneImageView() - : mKeyguardBottomArea.getCameraImageView(); + ? mKeyguardBottomArea.getPhonePreview() + : mKeyguardBottomArea.getCameraPreview(); } @Override @@ -1262,6 +1289,22 @@ public class NotificationPanelView extends PanelView implements } @Override + protected boolean fullyExpandedClearAllVisible() { + return mNotificationStackScroller.isDismissViewNotGone() + && mNotificationStackScroller.isScrolledToBottom(); + } + + @Override + protected boolean isClearAllVisible() { + return mNotificationStackScroller.isDismissViewVisible(); + } + + @Override + protected int getClearAllHeight() { + return mNotificationStackScroller.getDismissViewHeight(); + } + + @Override protected boolean isTrackingBlocked() { return mConflictingQsExpansionGesture && mQsExpanded; } @@ -1282,4 +1325,27 @@ public class NotificationPanelView extends PanelView implements public boolean shouldDelayChildPressedState() { return true; } + + public boolean isLaunchTransitionFinished() { + return mIsLaunchTransitionFinished; + } + + public boolean isLaunchTransitionRunning() { + return mIsLaunchTransitionRunning; + } + + public void setLaunchTransitionEndRunnable(Runnable r) { + mLaunchAnimationEndRunnable = r; + } + + public void setEmptyDragAmount(float amount) { + float factor = 1f; + if (mNotificationStackScroller.getNotGoneChildCount() > 0) { + factor = 0.6f; + } else if (!mStatusBar.hasNotifications()) { + factor = 0.4f; + } + mEmptyDragAmount = amount * factor; + positionClockAndNotifications(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java index f41e78dff08c..7c6e47cf257a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java @@ -17,23 +17,71 @@ package com.android.systemui.statusbar.phone; import android.content.Context; +import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; +import android.view.View; +import android.view.ViewStub; import android.widget.FrameLayout; +import com.android.systemui.R; + /** * The container with notification stack scroller and quick settings inside. */ -public class NotificationsQuickSettingsContainer extends FrameLayout { +public class NotificationsQuickSettingsContainer extends FrameLayout + implements ViewStub.OnInflateListener { + + private View mScrollView; + private View mUserSwitcher; + private View mStackScroller; + private boolean mInflated; public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) { super(context, attrs); } @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mScrollView = findViewById(R.id.scroll_view); + mStackScroller = findViewById(R.id.notification_stack_scroller); + ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher); + userSwitcher.setOnInflateListener(this); + mUserSwitcher = userSwitcher; + } + + @Override protected boolean fitSystemWindows(Rect insets) { setPadding(0, 0, 0, insets.bottom); insets.bottom = 0; return true; } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE; + + // Invert the order of the scroll view and user switcher such that the notifications receive + // touches first but the panel gets drawn above. + if (child == mScrollView) { + return super.drawChild(canvas, mStackScroller, drawingTime); + } else if (child == mStackScroller) { + return super.drawChild(canvas, userSwitcherVisible ? mUserSwitcher : mScrollView, + drawingTime); + } else if (child == mUserSwitcher) { + return super.drawChild(canvas, userSwitcherVisible ? mScrollView : mUserSwitcher, + drawingTime); + } else { + return super.drawChild(canvas, child, drawingTime); + } + } + + @Override + public void onInflate(ViewStub stub, View inflated) { + if (stub == mUserSwitcher) { + mUserSwitcher = inflated; + mInflated = true; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 7fb56935e3db..3ec23955fdb5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -462,6 +462,16 @@ public abstract class PanelView extends FrameLayout { protected void fling(float vel, boolean expand) { cancelPeek(); float target = expand ? getMaxPanelHeight() : 0.0f; + + // Hack to make the expand transition look nice when clear all button is visible - we make + // the animation only to the last notification, and then jump to the maximum panel height so + // clear all just fades in and the decelerating motion is towards the last notification. + final boolean clearAllExpandHack = expand && fullyExpandedClearAllVisible() + && mExpandedHeight < getMaxPanelHeight() - getClearAllHeight() + && !isClearAllVisible(); + if (clearAllExpandHack) { + target = getMaxPanelHeight() - getClearAllHeight(); + } if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) { notifyExpandingFinished(); return; @@ -490,9 +500,32 @@ public abstract class PanelView extends FrameLayout { @Override public void onAnimationEnd(Animator animation) { - mHeightAnimator = null; - if (!mCancelled) { - notifyExpandingFinished(); + if (clearAllExpandHack && !mCancelled) { + mHeightAnimator = createHeightAnimator(getMaxPanelHeight()); + mHeightAnimator.setInterpolator(mLinearOutSlowInInterpolator); + mHeightAnimator.setDuration(350); + mHeightAnimator.addListener(new AnimatorListenerAdapter() { + private boolean mCancelled; + + @Override + public void onAnimationCancel(Animator animation) { + mCancelled = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + mHeightAnimator = null; + if (!mCancelled) { + notifyExpandingFinished(); + } + } + }); + mHeightAnimator.start(); + } else { + mHeightAnimator = null; + if (!mCancelled) { + notifyExpandingFinished(); + } } } }); @@ -878,4 +911,16 @@ public abstract class PanelView extends FrameLayout { protected abstract float getPeekHeight(); protected abstract float getCannedFlingDurationFactor(); + + /** + * @return whether "Clear all" button will be visible when the panel is fully expanded + */ + protected abstract boolean fullyExpandedClearAllVisible(); + + protected abstract boolean isClearAllVisible(); + + /** + * @return the height of the clear all button, in pixels + */ + protected abstract int getClearAllHeight(); } 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 e4e67c951475..044f69c988c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -53,7 +53,6 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.inputmethodservice.InputMethodService; @@ -63,6 +62,7 @@ import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.MediaSessionManager; import android.media.session.PlaybackState; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -92,11 +92,13 @@ import android.view.ViewPropertyAnimator; import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.WindowManager; +import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; @@ -115,6 +117,7 @@ import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.ActivatableNotificationView; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.DismissView; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.GestureRecorder; @@ -126,6 +129,7 @@ import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.SpeedBumpView; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; import com.android.systemui.statusbar.policy.BluetoothControllerImpl; @@ -155,7 +159,7 @@ import java.util.Collections; import java.util.List; public class PhoneStatusBar extends BaseStatusBar implements DemoMode, - DragDownHelper.OnDragDownListener, ActivityStarter { + DragDownHelper.DragDownCallback, ActivityStarter { static final String TAG = "PhoneStatusBar"; public static final boolean DEBUG = BaseStatusBar.DEBUG; public static final boolean SPEW = false; @@ -201,6 +205,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) .build(); + public static final int FADE_KEYGUARD_START_DELAY = 100; + public static final int FADE_KEYGUARD_DURATION = 300; + PhoneStatusBarPolicy mIconPolicy; // These are no longer handled by the policy, because we need custom strategies for them @@ -217,6 +224,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, KeyguardUserSwitcher mKeyguardUserSwitcher; FlashlightController mFlashlightController; UserSwitcherController mUserSwitcherController; + NextAlarmController mNextAlarmController; KeyguardMonitor mKeyguardMonitor; int mNaturalBarHeight = -1; @@ -275,7 +283,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private long mKeyguardFadingAwayDuration; int mKeyguardMaxNotificationCount; - View mDateTimeView; // carrier/wifi label private TextView mCarrierLabel; @@ -397,6 +404,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private boolean mDozing; private Interpolator mLinearOutSlowIn; + private Interpolator mLinearInterpolator = new LinearInterpolator(); + private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator(); private Interpolator mAlphaIn = new PathInterpolator(0f, 0.2f, 1f, 1f); private Interpolator mAlphaOut = new PathInterpolator(0f, 0f, 0.8f, 1f); @@ -441,6 +450,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private final ShadeUpdates mShadeUpdates = new ShadeUpdates(); private int mDrawCount; + private Runnable mLaunchTransitionEndRunnable; + private boolean mLaunchTransitionFadingAway; + + private boolean mHasNotifications; private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD | ViewState.LOCATION_TOP_STACK_PEEKING @@ -666,6 +679,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_speed_bump, mStackScroller, false); mStackScroller.setSpeedBumpView(speedBump); + mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( + R.layout.status_bar_notification_dismiss_all, mStackScroller, false); + mDismissView.setOnButtonClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + clearAllNotifications(); + } + }); + mStackScroller.setDismissView(mDismissView); mExpandedContents = mStackScroller; mScrimController = new ScrimController(mStatusBarWindow.findViewById(R.id.scrim_behind), @@ -682,12 +704,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, (KeyguardIndicationTextView) mStatusBarWindow.findViewById( R.id.keyguard_indication_text)); - mDateTimeView = mHeader.findViewById(R.id.datetime); - if (mDateTimeView != null) { - mDateTimeView.setOnClickListener(mClockClickListener); - mDateTimeView.setEnabled(true); - } - mTickerEnabled = res.getBoolean(R.bool.enable_ticker); if (mTickerEnabled) { final ViewStub tickerStub = (ViewStub) mStatusBarView.findViewById(R.id.ticker_stub); @@ -731,9 +747,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, final SignalClusterView signalCluster = (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster); - mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, - (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mHeader); - mNetworkController.addSignalCluster(signalCluster); signalCluster.setNetworkController(mNetworkController); final boolean isAPhone = mNetworkController.hasVoiceCallingFeature(); @@ -767,8 +780,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mFlashlightController = new FlashlightController(mContext); mKeyguardBottomArea.setFlashlightController(mFlashlightController); mUserSwitcherController = new UserSwitcherController(mContext); + mNextAlarmController = new NextAlarmController(mContext); mKeyguardMonitor = new KeyguardMonitor(); + mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, + (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mHeader, + mUserSwitcherController); + + // Set up the quick settings tile panel mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel); if (mQSPanel != null) { @@ -793,6 +812,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mUserInfoController.reloadUserInfo(); mHeader.setBatteryController(mBatteryController); + mHeader.setNextAlarmController(mNextAlarmController); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mBroadcastReceiver.onReceive(mContext, @@ -816,6 +836,73 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return mStatusBarView; } + private void clearAllNotifications() { + + // animate-swipe all dismissable notifications, then animate the shade closed + int numChildren = mStackScroller.getChildCount(); + + final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren); + for (int i = 0; i < numChildren; i++) { + final View child = mStackScroller.getChildAt(i); + if (mStackScroller.canChildBeDismissed(child)) { + if (child.getVisibility() == View.VISIBLE) { + viewsToHide.add(child); + } + } + } + if (viewsToHide.isEmpty()) { + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); + return; + } + + mPostCollapseCleanup = new Runnable() { + @Override + public void run() { + try { + mBarService.onClearAllNotifications(mCurrentUserId); + } catch (Exception ex) { } + } + }; + + performDismissAllAnimations(viewsToHide); + + } + + private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { + Runnable animationFinishAction = new Runnable() { + @Override + public void run() { + mStackScroller.post(new Runnable() { + @Override + public void run() { + mStackScroller.setDismissAllInProgress(false); + } + }); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); + } + }; + + // let's disable our normal animations + mStackScroller.setDismissAllInProgress(true); + + // Decrease the delay for every row we animate to give the sense of + // accelerating the swipes + int rowDelayDecrement = 10; + int currentDelay = 140; + int totalDelay = 0; + int numItems = hideAnimatedList.size(); + for (int i = 0; i < numItems; i++) { + View view = hideAnimatedList.get(i); + Runnable endRunnable = null; + if (i == numItems - 1) { + endRunnable = animationFinishAction; + } + mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260); + currentDelay = Math.max(50, currentDelay - rowDelayDecrement); + totalDelay += currentDelay; + } + } + /** * Hack to improve glyph rasterization for scaled text views. */ @@ -1228,8 +1315,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, updateExpandedViewPos(EXPANDED_LEAVE_ALONE); if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 - && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) { - animateCollapsePanels(); + && !mNotificationPanel.isTracking()) { + if (mState == StatusBarState.SHADE) { + animateCollapsePanels(); + } else if (mState == StatusBarState.SHADE_LOCKED) { + goToKeyguard(); + } } } setAreThereNotifications(); @@ -1326,10 +1417,32 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } updateRowStates(); updateSpeedbump(); + updateClearAll(); + mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup); mShadeUpdates.check(); } + private void updateClearAll() { + boolean showDismissView = false; + if (mState != StatusBarState.KEYGUARD) { + for (int i = 0; i < mNotificationData.size(); i++) { + Entry entry = mNotificationData.get(i); + if (entry.row.getParent() == null) { + // This view isn't even added, so the stack scroller doesn't + // know about it. Ignore completely. + continue; + } + if (entry.row.getVisibility() != View.GONE && entry.expanded != null + && entry.notification.isClearable()) { + showDismissView = true; + break; + } + } + } + mStackScroller.updateDismissView(showDismissView); + } + private void updateSpeedbump() { int speedbumpIndex = -1; int currentIndex = 0; @@ -1503,6 +1616,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, findAndUpdateMediaNotifications(); updateCarrierLabelVisibility(false); + + // TODO: Multiuser handling! + mHasNotifications = any; } public void findAndUpdateMediaNotifications() { @@ -1518,7 +1634,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, final MediaSession.Token token = entry.notification.getNotification().extras .getParcelable(Notification.EXTRA_MEDIA_SESSION); if (token != null) { - controller = new MediaController(token); + controller = new MediaController(mContext, token); if (controller != null) { // we've got a live one, here mediaNotification = entry; @@ -1548,7 +1664,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, continue; default: // now to see if we have one like this - final String pkg = aController.getSessionInfo().getPackageName(); + final String pkg = aController.getPackageName(); for (int i = 0; i < N; i++) { final Entry entry = mNotificationData.get(i); @@ -1693,7 +1809,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, + " to " + mBackdropBack.getDrawable()); } - mBackdropFront.animate().withLayer() + mBackdropFront.animate() .setDuration(250) .alpha(0f).withEndAction(mHideBackdropFront); } @@ -1705,16 +1821,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); } - mBackdrop.animate().withLayer() - .alpha(0f).withEndAction(new Runnable() { - @Override - public void run() { - mBackdrop.setVisibility(View.GONE); - mBackdropFront.animate().cancel(); - mBackdropBack.animate().cancel(); - mHandler.post(mHideBackdropFront); - } - }); + mBackdrop.animate() + .alpha(0f) + .setInterpolator(mBackdropInterpolator) + .setDuration(300) + .setStartDelay(0) + .withEndAction(new Runnable() { + @Override + public void run() { + mBackdrop.setVisibility(View.GONE); + mBackdropFront.animate().cancel(); + mBackdropBack.animate().cancel(); + mHandler.post(mHideBackdropFront); + } + }); + if (mKeyguardFadingAway) { + mBackdrop.animate() + + // Make it disappear faster, as the focus should be on the activity behind. + .setDuration(mKeyguardFadingAwayDuration / 2) + .setStartDelay(mKeyguardFadingAwayDelay) + .setInterpolator(mLinearInterpolator) + .start(); + } } } } @@ -1728,7 +1857,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } private int adjustDisableFlags(int state) { - if (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit) { + if (!mLaunchTransitionFadingAway + && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) { state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS; state |= StatusBarManager.DISABLE_SYSTEM_INFO; } @@ -1995,6 +2125,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void animateCollapsePanels(int flags, boolean force) { if (!force && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { + if (mPostCollapseCleanup != null) { + mPostCollapseCleanup.run(); + mPostCollapseCleanup = null; + } return; } if (SPEW) { @@ -2217,6 +2351,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override // CommandQueue + public void buzzBeepBlinked() { + if (mDozeServiceHost != null) { + mDozeServiceHost.fireBuzzBeepBlinked(); + } + } + + @Override // CommandQueue public void setSystemUiVisibility(int vis, int mask) { final int oldVal = mSystemUiVisibility; final int newVal = (oldVal&~mask) | (vis&mask); @@ -2666,6 +2807,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mBatteryController != null) { mBatteryController.dump(fd, pw, args); } + if (mNextAlarmController != null) { + mNextAlarmController.dump(fd, pw, args); + } } private String hunStateToString(Entry entry) { @@ -2722,16 +2866,25 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned) { if (onlyProvisioned && !isDeviceProvisioned()) return; + final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); dismissKeyguardThenExecute(new OnDismissAction() { @Override public boolean onDismiss() { - try { - // Dismiss the lock screen when Settings starts. - ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); - } catch (RemoteException e) { - } - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + AsyncTask.execute(new Runnable() { + public void run() { + try { + intent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + mContext.startActivityAsUser( + intent, new UserHandle(UserHandle.USER_CURRENT)); + if (keyguardShowing) { + mWindowManagerService.overridePendingAppTransition( + null, 0, 0, null); + } + } catch (RemoteException e) { + } + } + }); animateCollapsePanels(); return DELAY_DISMISS_TO_ACTIVITY_LAUNCH; @@ -2752,11 +2905,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, String action = intent.getAction(); if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { int flags = CommandQueue.FLAG_EXCLUDE_NONE; - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - String reason = intent.getStringExtra("reason"); - if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { - flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; - } + String reason = intent.getStringExtra("reason"); + if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { + flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; } animateCollapsePanels(flags); } @@ -2795,9 +2946,20 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, }; @Override - protected void dismissKeyguardThenExecute(OnDismissAction action) { + protected void dismissKeyguardThenExecute(final OnDismissAction action) { if (mStatusBarKeyguardViewManager.isShowing()) { - mStatusBarKeyguardViewManager.dismissWithAction(action); + if (UnlockMethodCache.getInstance(mContext).isMethodInsecure() + && mNotificationPanel.isLaunchTransitionRunning()) { + action.onDismiss(); + mNotificationPanel.setLaunchTransitionEndRunnable(new Runnable() { + @Override + public void run() { + mStatusBarKeyguardViewManager.dismiss(); + } + }); + } else { + mStatusBarKeyguardViewManager.dismissWithAction(action); + } } else { action.onDismiss(); } @@ -3170,6 +3332,52 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mLeaveOpenOnKeyguardHide = false; } + public boolean isInLaunchTransition() { + return mNotificationPanel.isLaunchTransitionRunning() + || mNotificationPanel.isLaunchTransitionFinished(); + } + + /** + * Fades the content of the keyguard away after the launch transition is done. + * + * @param beforeFading the runnable to be run when the circle is fully expanded and the fading + * starts + * @param endRunnable the runnable to be run when the transition is done + */ + public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, + final Runnable endRunnable) { + Runnable hideRunnable = new Runnable() { + @Override + public void run() { + mLaunchTransitionFadingAway = true; + if (beforeFading != null) { + beforeFading.run(); + } + mNotificationPanel.setAlpha(1); + mNotificationPanel.animate() + .alpha(0) + .setStartDelay(FADE_KEYGUARD_START_DELAY) + .setDuration(FADE_KEYGUARD_DURATION) + .withLayer() + .withEndAction(new Runnable() { + @Override + public void run() { + mNotificationPanel.setAlpha(1); + if (endRunnable != null) { + endRunnable.run(); + } + mLaunchTransitionFadingAway = false; + } + }); + } + }; + if (mNotificationPanel.isLaunchTransitionRunning()) { + mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable); + } else { + hideRunnable.run(); + } + } + public void hideKeyguard() { setBarState(StatusBarState.SHADE); if (mLeaveOpenOnKeyguardHide) { @@ -3204,8 +3412,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private void updatePublicMode() { setLockscreenPublicMode( - (mStatusBarKeyguardViewManager.isShowing() || - mStatusBarKeyguardViewManager.isOccluded()) + (mStatusBarKeyguardViewManager.isShowing() || + mStatusBarKeyguardViewManager.isOccluded()) && mStatusBarKeyguardViewManager.isSecure()); } @@ -3315,7 +3523,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private void showBouncer() { if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { - mWaitingForKeyguardExit = true; + mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing(); mStatusBarKeyguardViewManager.dismiss(); } } @@ -3358,6 +3566,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } public void onTrackingStarted() { + if (mPostCollapseCleanup != null) { + mPostCollapseCleanup.run(); + mPostCollapseCleanup = null; + } } public void onUnlockHintStarted() { @@ -3397,8 +3609,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ @Override - public void onDraggedDown(View startingChild) { - goToLockedShade(startingChild); + public boolean onDraggedDown(View startingChild) { + if (mHasNotifications) { + + // We have notifications, go to locked shade. + goToLockedShade(startingChild); + return true; + } else { + + // No notifications - abort gesture. + return false; + } } @Override @@ -3406,6 +3627,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStackScroller.setDimmed(true /* dimmed */, true /* animated */); } + @Override public void onThresholdReached() { mStackScroller.setDimmed(false /* dimmed */, true /* animate */); } @@ -3415,6 +3637,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStackScroller.removeLongPressCallback(); } + @Override + public void setEmptyDragAmount(float amount) { + mNotificationPanel.setEmptyDragAmount(amount); + } + /** * If secure with redaction: Show bouncer, go to unlocked shade. * @@ -3525,6 +3752,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, notifyUiVisibilityChanged(mSystemUiVisibility); } + public boolean hasNotifications() { + return mHasNotifications; + } + private final class ShadeUpdates { private final ArraySet<String> mVisibleNotifications = new ArraySet<String>(); private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>(); @@ -3562,6 +3793,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private DozeService mCurrentDozeService; + public void fireBuzzBeepBlinked() { + for (Callback callback : mCallbacks) { + callback.onBuzzBeepBlinked(); + } + } + public void fireNewNotifications() { for (Callback callback : mCallbacks) { callback.onNewNotifications(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index cf930bddead3..eb4240134520 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -71,7 +71,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener { private boolean mAnimationStarted; private boolean mDozing; private int mTeasesRemaining; - private final Interpolator mInterpolator = new DecelerateInterpolator(); public ScrimController(View scrimBehind, View scrimInFront) { @@ -149,7 +148,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener { } private void updateScrims() { - if ((!mKeyguardShowing && !mBouncerShowing) || mAnimateKeyguardFadingOut) { + if (mAnimateKeyguardFadingOut) { + setScrimInFrontColor(0f); + setScrimBehindColor(0f); + }else if (!mKeyguardShowing && !mBouncerShowing) { updateScrimNormal(); setScrimInFrontColor(0); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 2f88e21c315a..27d66d9c2e56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import android.app.AlarmClockInfo; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.graphics.Outline; @@ -31,17 +33,20 @@ import android.widget.RelativeLayout; import android.widget.Switch; import android.widget.TextView; +import com.android.keyguard.KeyguardStatusView; import com.android.systemui.R; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; +import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.UserInfoController; /** * The view to manage the header area in the expanded status bar. */ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener, - BatteryController.BatteryStateChangeCallback { + BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback { private boolean mExpanded; private boolean mListening; @@ -51,7 +56,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private ViewGroup mSystemIconsContainer; private View mSystemIconsSuperContainer; - private View mDateTime; + private View mDateGroup; + private View mClock; private View mTime; private View mAmPm; private View mKeyguardCarrierText; @@ -67,9 +73,12 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private Switch mQsDetailHeaderSwitch; private View mEmergencyCallsOnly; private TextView mBatteryLevel; + private TextView mAlarmStatus; private boolean mShowEmergencyCallsOnly; private boolean mKeyguardUserSwitcherShowing; + private boolean mAlarmShowing; + private AlarmClockInfo mNextAlarm; private int mCollapsedHeight; private int mExpandedHeight; @@ -83,9 +92,13 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private int mMultiUserKeyguardMargin; private int mSystemIconsSwitcherHiddenExpandedMargin; private int mClockMarginBottomExpanded; + private int mClockMarginBottomCollapsed; private int mMultiUserSwitchWidthCollapsed; private int mMultiUserSwitchWidthExpanded; + private int mMultiUserSwitchWidthKeyguard; private int mBatteryPaddingEnd; + private int mBatteryMarginExpanded; + private int mBatteryMarginKeyguard; /** * In collapsed QS, the clock and avatar are scaled down a bit post-layout to allow for a nice @@ -93,10 +106,13 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL */ private float mClockCollapsedScaleFactor; private float mAvatarCollapsedScaleFactor; + private float mAvatarKeyguardScaleFactor; private ActivityStarter mActivityStarter; private BatteryController mBatteryController; + private NextAlarmController mNextAlarmController; private QSPanel mQSPanel; + private KeyguardUserSwitcher mKeyguardUserSwitcher; private final Rect mClipBounds = new Rect(); private final StatusIconClipper mStatusIconClipper = new StatusIconClipper(); @@ -111,7 +127,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container); mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container); mSystemIconsSuperContainer.setOnClickListener(this); - mDateTime = findViewById(R.id.datetime); + mDateGroup = findViewById(R.id.date_group); + mClock = findViewById(R.id.clock); mTime = findViewById(R.id.time_view); mAmPm = findViewById(R.id.am_pm_view); mKeyguardCarrierText = findViewById(R.id.keyguard_carrier_text); @@ -127,6 +144,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle); mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only); mBatteryLevel = (TextView) findViewById(R.id.battery_level); + mAlarmStatus = (TextView) findViewById(R.id.alarm_status); + mAlarmStatus.setOnClickListener(this); loadDimens(); updateVisibilities(); updateClockScale(); @@ -173,18 +192,29 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL R.dimen.system_icons_switcher_hidden_expanded_margin); mClockMarginBottomExpanded = getResources().getDimensionPixelSize(R.dimen.clock_expanded_bottom_margin); + mClockMarginBottomCollapsed = + getResources().getDimensionPixelSize(R.dimen.clock_collapsed_bottom_margin); mMultiUserSwitchWidthCollapsed = getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_collapsed); mMultiUserSwitchWidthExpanded = getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_expanded); + mMultiUserSwitchWidthKeyguard = + getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_keyguard); mAvatarCollapsedScaleFactor = getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_collapsed_size) / (float) mMultiUserAvatar.getLayoutParams().width; + mAvatarKeyguardScaleFactor = + getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size) + / (float) mMultiUserAvatar.getLayoutParams().width; mClockCollapsedScaleFactor = (float) getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size) / (float) getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size); mBatteryPaddingEnd = getResources().getDimensionPixelSize(R.dimen.battery_level_padding_end); + mBatteryMarginExpanded = + getResources().getDimensionPixelSize(R.dimen.header_battery_margin_expanded); + mBatteryMarginKeyguard = + getResources().getDimensionPixelSize(R.dimen.header_battery_margin_keyguard); } public void setActivityStarter(ActivityStarter activityStarter) { @@ -195,6 +225,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mBatteryController = batteryController; } + public void setNextAlarmController(NextAlarmController nextAlarmController) { + mNextAlarmController = nextAlarmController; + } + public int getCollapsedHeight() { return mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight; } @@ -208,7 +242,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL return; } mListening = listening; - updateBatteryListening(); + updateListeners(); } public void setExpanded(boolean expanded, boolean overscrolled) { @@ -232,6 +266,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL updateAvatarScale(); updateClockLp(); updateBatteryLevelPaddingEnd(); + updateBatteryLevelLp(); mStatusIconClipper.update(); } } @@ -239,7 +274,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private void updateHeights() { boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded; int height; - if (mExpanded) { + if (mExpanded && !mOverscrolled) { height = mExpandedHeight; } else if (onKeyguardAndCollapsed) { height = mKeyguardHeight; @@ -280,10 +315,15 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } else { setBackgroundResource(R.drawable.notification_header_bg); } - mDateTime.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE); + mDateGroup.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE); + mClock.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE); mKeyguardCarrierText.setVisibility(onKeyguardAndCollapsed ? View.VISIBLE : View.GONE); - mDateCollapsed.setVisibility(mExpanded && !mOverscrolled ? View.GONE : View.VISIBLE); - mDateExpanded.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE); + mDateCollapsed.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing + ? View.VISIBLE : View.GONE); + mDateExpanded.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing + ? View.GONE : View.VISIBLE); + mAlarmStatus.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing + ? View.VISIBLE : View.GONE); mSettingsButton.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE); mQsDetailHeader.setVisibility(mExpanded ? View.VISIBLE : View.GONE); if (mStatusIcons != null) { @@ -298,6 +338,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL ? VISIBLE : GONE); mBatteryLevel.setVisibility(mKeyguardShowing && mCharging || mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE); + if (mExpanded && !mOverscrolled && mKeyguardUserSwitcherShowing) { + mKeyguardUserSwitcher.hide(); + } } private void updateSystemIconsLayoutParams() { @@ -314,21 +357,26 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mSystemIconsSuperContainer.setLayoutParams(lp); } - private void updateBatteryListening() { + private void updateListeners() { if (mListening) { mBatteryController.addStateChangedCallback(this); + mNextAlarmController.addStateChangedCallback(this); } else { mBatteryController.removeStateChangedCallback(this); + mNextAlarmController.removeStateChangedCallback(this); } } private void updateAvatarScale() { - if (!mExpanded || mOverscrolled) { - mMultiUserSwitch.setScaleX(mAvatarCollapsedScaleFactor); - mMultiUserSwitch.setScaleY(mAvatarCollapsedScaleFactor); - } else { + if (mExpanded && !mOverscrolled) { mMultiUserSwitch.setScaleX(1f); mMultiUserSwitch.setScaleY(1f); + } else if (mKeyguardShowing) { + mMultiUserSwitch.setScaleX(mAvatarKeyguardScaleFactor); + mMultiUserSwitch.setScaleY(mAvatarKeyguardScaleFactor); + } else { + mMultiUserSwitch.setScaleX(mAvatarCollapsedScaleFactor); + mMultiUserSwitch.setScaleY(mAvatarCollapsedScaleFactor); } } @@ -370,11 +418,26 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL // could not care less } + @Override + public void onNextAlarmChanged(AlarmClockInfo nextAlarm) { + mNextAlarm = nextAlarm; + if (nextAlarm != null) { + mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm)); + } + mAlarmShowing = nextAlarm != null; + updateVisibilities(); + } + + private void updateClickTargets() { setClickable(!mKeyguardShowing || mExpanded); - mDateTime.setClickable(mExpanded); - mMultiUserSwitch.setClickable(mExpanded); + + boolean keyguardSwitcherAvailable = + mKeyguardUserSwitcher != null && mKeyguardShowing && !mExpanded; + mMultiUserSwitch.setClickable(mExpanded || keyguardSwitcherAvailable); + mMultiUserSwitch.setKeyguardMode(keyguardSwitcherAvailable); mSystemIconsSuperContainer.setClickable(mExpanded); + mAlarmStatus.setClickable(mNextAlarm != null && mNextAlarm.getShowIntent() != null); } private void updateZTranslation() { @@ -395,29 +458,29 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } private void updateClockLp() { - int marginBottom = mExpanded && !mOverscrolled ? mClockMarginBottomExpanded : 0; - LayoutParams lp = (LayoutParams) mDateTime.getLayoutParams(); - int rule = mExpanded && !mOverscrolled ? TRUE : 0; - if (marginBottom != lp.bottomMargin - || lp.getRules()[RelativeLayout.ALIGN_PARENT_BOTTOM] != rule) { + int marginBottom = mExpanded && !mOverscrolled + ? mClockMarginBottomExpanded + : mClockMarginBottomCollapsed; + LayoutParams lp = (LayoutParams) mDateGroup.getLayoutParams(); + if (marginBottom != lp.bottomMargin) { lp.bottomMargin = marginBottom; - lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, rule); - mDateTime.setLayoutParams(lp); + mDateGroup.setLayoutParams(lp); } } private void updateMultiUserSwitch() { int marginEnd; + int width; if (mExpanded && !mOverscrolled) { marginEnd = mMultiUserExpandedMargin; + width = mMultiUserSwitchWidthExpanded; } else if (mKeyguardShowing) { marginEnd = mMultiUserKeyguardMargin; + width = mMultiUserSwitchWidthKeyguard; } else { marginEnd = mMultiUserCollapsedMargin; + width = mMultiUserSwitchWidthCollapsed; } - int width = mExpanded && !mOverscrolled - ? mMultiUserSwitchWidthExpanded - : mMultiUserSwitchWidthCollapsed; MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams(); if (marginEnd != lp.getMarginEnd() || lp.width != width) { lp.setMarginEnd(marginEnd); @@ -426,6 +489,17 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } } + private void updateBatteryLevelLp() { + int marginStart = mExpanded && !mOverscrolled + ? mBatteryMarginExpanded + : mBatteryMarginKeyguard; + MarginLayoutParams lp = (MarginLayoutParams) mBatteryLevel.getLayoutParams(); + if (marginStart != lp.getMarginStart()) { + lp.setMarginStart(marginStart); + mBatteryLevel.setLayoutParams(lp); + } + } + public void setExpansion(float t) { float height = mCollapsedHeight + t * (mExpandedHeight - mCollapsedHeight); if (height < mCollapsedHeight) { @@ -472,6 +546,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL updateMultiUserSwitch(); updateClickTargets(); updateBatteryLevelPaddingEnd(); + updateAvatarScale(); mStatusIconClipper.update(); } @@ -490,6 +565,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL startSettingsActivity(); } else if (v == mSystemIconsSuperContainer) { startBatteryActivity(); + } else if (v == mAlarmStatus && mNextAlarm != null) { + PendingIntent showIntent = mNextAlarm.getShowIntent(); + if (showIntent != null && showIntent.isActivity()) { + mActivityStarter.startActivity(showIntent.getIntent()); + } } } @@ -509,6 +589,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mMultiUserSwitch.setQsPanel(qsp); } + public void setKeyguarUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { + mKeyguardUserSwitcher = keyguardUserSwitcher; + mMultiUserSwitch.setKeyguardUserSwitcher(keyguardUserSwitcher); + } + @Override public boolean shouldDelayChildPressedState() { return true; @@ -522,7 +607,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } public void setKeyguardUserSwitcherShowing(boolean showing) { - // STOPSHIP: NOT CALLED PROPERLY WHEN GOING TO FULL SHADE AND RETURNING!?! mKeyguardUserSwitcherShowing = showing; updateVisibilities(); updateSystemIconsLayoutParams(); @@ -553,8 +637,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } public void update() { - final boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded; - mSystemIconsContainer.setClipBounds(onKeyguardAndCollapsed ? null : mClipBounds); + final boolean collapsedKeyguard = mKeyguardShowing && !mExpanded; + final boolean expanded = mExpanded && !mOverscrolled; + mSystemIconsContainer.setClipBounds(collapsedKeyguard || expanded ? null : mClipBounds); } } @@ -599,7 +684,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private void handleShowingDetail(final QSTile.DetailAdapter detail) { final boolean showingDetail = detail != null; - transition(mDateTime, !showingDetail); + transition(mClock, !showingDetail); + transition(mDateGroup, !showingDetail); transition(mQsDetailHeader, showingDetail); if (showingDetail) { mQsDetailHeaderTitle.setText(detail.getTitle()); 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 93dcf9015b66..af21f25438dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -176,6 +176,19 @@ public class StatusBarKeyguardViewManager { } public void setOccluded(boolean occluded) { + if (occluded && !mOccluded && mShowing) { + if (mPhoneStatusBar.isInLaunchTransition()) { + mOccluded = true; + mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */, + new Runnable() { + @Override + public void run() { + mStatusBarWindowManager.setKeyguardOccluded(true); + } + }); + return; + } + } mOccluded = occluded; mStatusBarWindowManager.setKeyguardOccluded(occluded); reset(); @@ -188,29 +201,50 @@ public class StatusBarKeyguardViewManager { /** * Hides the keyguard view */ - public void hide(long startTime, long fadeoutDuration) { + public void hide(long startTime, final long fadeoutDuration) { mShowing = false; long uptimeMillis = SystemClock.uptimeMillis(); - long delay = startTime - uptimeMillis; - if (delay < 0) { - delay = 0; + long delay = Math.max(0, startTime - uptimeMillis); + + if (mPhoneStatusBar.isInLaunchTransition() ) { + mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() { + @Override + public void run() { + mStatusBarWindowManager.setKeyguardShowing(false); + mStatusBarWindowManager.setKeyguardFadingAway(true); + mBouncer.animateHide(PhoneStatusBar.FADE_KEYGUARD_START_DELAY, + PhoneStatusBar.FADE_KEYGUARD_DURATION); + updateStates(); + mScrimController.animateKeyguardFadingOut( + PhoneStatusBar.FADE_KEYGUARD_START_DELAY, + PhoneStatusBar.FADE_KEYGUARD_DURATION, null); + } + }, new Runnable() { + @Override + public void run() { + mPhoneStatusBar.hideKeyguard(); + mStatusBarWindowManager.setKeyguardFadingAway(false); + mViewMediatorCallback.keyguardGone(); + } + }); + } else { + mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration); + mPhoneStatusBar.hideKeyguard(); + mStatusBarWindowManager.setKeyguardFadingAway(true); + mStatusBarWindowManager.setKeyguardShowing(false); + mBouncer.animateHide(delay, fadeoutDuration); + mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() { + @Override + public void run() { + mStatusBarWindowManager.setKeyguardFadingAway(false); + mPhoneStatusBar.finishKeyguardFadingAway(); + } + }); + mViewMediatorCallback.keyguardGone(); + updateStates(); } - mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration); - mPhoneStatusBar.hideKeyguard(); - mStatusBarWindowManager.setKeyguardFadingAway(true); - mStatusBarWindowManager.setKeyguardShowing(false); - mBouncer.animateHide(delay, fadeoutDuration); - mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() { - @Override - public void run() { - mStatusBarWindowManager.setKeyguardFadingAway(false); - mPhoneStatusBar.finishKeyguardFadingAway(); - } - }); - mViewMediatorCallback.keyguardGone(); - updateStates(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 7f27a0c8179b..86a662241d5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -29,12 +29,11 @@ public class SystemUIDialog extends AlertDialog { public SystemUIDialog(Context context) { super(context, R.style.Theme_SystemUI_Dialog); - getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL); getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); WindowManager.LayoutParams attrs = getWindow().getAttributes(); - attrs.setTitle("SystemUIDialog"); + attrs.setTitle(getClass().getSimpleName()); getWindow().setAttributes(attrs); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java index e05e34bcbe37..36cfb86d60e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java @@ -77,7 +77,7 @@ public class FlashlightController { public void initialize() { try { mCameraId = getCameraId(); - } catch (CameraAccessException e) { + } catch (Throwable e) { Log.e(TAG, "Couldn't initialize.", e); return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java index f3ff8ad7b092..ac260dbb39a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java @@ -176,11 +176,9 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. @Override public void onAttachedToWindow() { - float densityScale = getResources().getDisplayMetrics().density; final ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext()); - float pagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop(); float touchSlop = viewConfiguration.getScaledTouchSlop(); - mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); + mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext()); mSwipeHelper.setMaxSwipeProgress(mMaxAlpha); mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java index a3f381907452..2be566cf5e83 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java @@ -16,62 +16,56 @@ package com.android.systemui.statusbar.policy; -import com.android.systemui.BitmapHelper; import com.android.systemui.R; import com.android.systemui.statusbar.phone.StatusBarHeaderView; import com.android.systemui.statusbar.phone.UserAvatarView; -import android.app.ActivityManagerNative; import android.content.Context; -import android.content.pm.UserInfo; -import android.graphics.Bitmap; -import android.os.AsyncTask; -import android.os.RemoteException; -import android.os.UserManager; -import android.util.Log; +import android.database.DataSetObserver; +import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; -import android.view.WindowManagerGlobal; import android.widget.TextView; -import java.util.ArrayList; -import java.util.List; - /** * Manages the user switcher on the Keyguard. */ -public class KeyguardUserSwitcher implements View.OnClickListener { +public class KeyguardUserSwitcher { private static final String TAG = "KeyguardUserSwitcher"; + private static final boolean ALWAYS_ON = false; + private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING = + "lockscreenSimpleUserSwitcher"; - private final Context mContext; private final ViewGroup mUserSwitcher; - private final UserManager mUserManager; private final StatusBarHeaderView mHeader; + private final Adapter mAdapter; + private final boolean mSimpleUserSwitcher; public KeyguardUserSwitcher(Context context, ViewStub userSwitcher, - StatusBarHeaderView header) { - mContext = context; - if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher)) { + StatusBarHeaderView header, UserSwitcherController userSwitcherController) { + if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) { mUserSwitcher = (ViewGroup) userSwitcher.inflate(); - mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mHeader = header; - refresh(); + mHeader.setKeyguarUserSwitcher(this); + mAdapter = new Adapter(context, userSwitcherController); + mAdapter.registerDataSetObserver(mDataSetObserver); + mSimpleUserSwitcher = Settings.Global.getInt(context.getContentResolver(), + SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0; } else { mUserSwitcher = null; - mUserManager = null; mHeader = null; + mAdapter = null; + mSimpleUserSwitcher = false; } } public void setKeyguard(boolean keyguard) { if (mUserSwitcher != null) { - // TODO: Cache showUserSwitcherOnKeyguard(). - if (keyguard && showUserSwitcherOnKeyguard()) { + if (keyguard && shouldExpandByDefault()) { show(); - refresh(); } else { hide(); } @@ -79,24 +73,11 @@ public class KeyguardUserSwitcher implements View.OnClickListener { } /** - * @return true if the user switcher should be shown on the lock screen. + * @return true if the user switcher should be expanded by default on the lock screen. * @see android.os.UserManager#isUserSwitcherEnabled() */ - private boolean showUserSwitcherOnKeyguard() { - // TODO: Set isEdu. The edu provisioning process can add settings to Settings.Global. - boolean isEdu = false; - if (isEdu) { - return true; - } - List<UserInfo> users = mUserManager.getUsers(true /* excludeDying */); - int N = users.size(); - int switchableUsers = 0; - for (int i = 0; i < N; i++) { - if (users.get(i).supportsSwitchTo()) { - switchableUsers++; - } - } - return switchableUsers > 1; + private boolean shouldExpandByDefault() { + return mSimpleUserSwitcher || mAdapter.getSwitchableUsers() > 1; } public void show() { @@ -107,7 +88,7 @@ public class KeyguardUserSwitcher implements View.OnClickListener { } } - private void hide() { + public void hide() { if (mUserSwitcher != null) { // TODO: animate mUserSwitcher.setVisibility(View.GONE); @@ -116,100 +97,76 @@ public class KeyguardUserSwitcher implements View.OnClickListener { } private void refresh() { - if (mUserSwitcher != null) { - new AsyncTask<Void, Void, ArrayList<UserData>>() { - @Override - protected ArrayList<UserData> doInBackground(Void... params) { - return loadUsers(); + final int childCount = mUserSwitcher.getChildCount(); + final int adapterCount = mAdapter.getCount(); + final int N = Math.max(childCount, adapterCount); + for (int i = 0; i < N; i++) { + if (i < adapterCount) { + View oldView = null; + if (i < childCount) { + oldView = mUserSwitcher.getChildAt(i); } - - @Override - protected void onPostExecute(ArrayList<UserData> userInfos) { - bind(userInfos); + View newView = mAdapter.getView(i, oldView, mUserSwitcher); + if (oldView == null) { + // We ran out of existing views. Add it at the end. + mUserSwitcher.addView(newView); + } else if (oldView != newView) { + // We couldn't rebind the view. Replace it. + mUserSwitcher.removeViewAt(i); + mUserSwitcher.addView(newView, i); } - }.execute((Void[]) null); + } else { + int lastIndex = mUserSwitcher.getChildCount() - 1; + mUserSwitcher.removeViewAt(lastIndex); + } } } - private void bind(ArrayList<UserData> userList) { - mUserSwitcher.removeAllViews(); - int N = userList.size(); - for (int i = 0; i < N; i++) { - mUserSwitcher.addView(inflateUser(userList.get(i))); + public final DataSetObserver mDataSetObserver = new DataSetObserver() { + @Override + public void onChanged() { + refresh(); } - // TODO: add Guest - // TODO: add (+) button - } + }; - private View inflateUser(UserData user) { - View v = LayoutInflater.from(mUserSwitcher.getContext()).inflate( - R.layout.keyguard_user_switcher_item, mUserSwitcher, false); - TextView name = (TextView) v.findViewById(R.id.name); - UserAvatarView picture = (UserAvatarView) v.findViewById(R.id.picture); - name.setText(user.userInfo.name); - picture.setActivated(user.isCurrent); - if (user.userInfo.isGuest()) { - picture.setDrawable(mContext.getResources().getDrawable(R.drawable.ic_account_circle)); - } else { - picture.setBitmap(user.userIcon); - } - v.setOnClickListener(this); - v.setTag(user.userInfo); - // TODO: mark which user is current for accessibility. - return v; - } + public static class Adapter extends UserSwitcherController.BaseUserAdapter implements + View.OnClickListener { - @Override - public void onClick(View v) { - switchUser(((UserInfo)v.getTag()).id); - } + private Context mContext; - // TODO: Factor out logic below and share with QS implementation. - - private ArrayList<UserData> loadUsers() { - ArrayList<UserInfo> users = (ArrayList<UserInfo>) mUserManager - .getUsers(true /* excludeDying */); - int N = users.size(); - ArrayList<UserData> result = new ArrayList<>(N); - int currentUser = -1; - try { - currentUser = ActivityManagerNative.getDefault().getCurrentUser().id; - } catch (RemoteException e) { - Log.e(TAG, "Couln't get current user.", e); + public Adapter(Context context, UserSwitcherController controller) { + super(controller); + mContext = context; } - final int avatarSize - = mContext.getResources().getDimensionPixelSize(R.dimen.max_avatar_size); - for (int i = 0; i < N; i++) { - UserInfo user = users.get(i); - if (user.supportsSwitchTo()) { - boolean isCurrent = user.id == currentUser; - final Bitmap picture = BitmapHelper.createCircularClip( - mUserManager.getUserIcon(user.id), - avatarSize, avatarSize); - result.add(new UserData(user, picture, isCurrent)); + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + UserSwitcherController.UserRecord item = getItem(position); + + if (convertView == null + || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) { + convertView = LayoutInflater.from(mContext).inflate( + R.layout.keyguard_user_switcher_item, parent, false); + convertView.setOnClickListener(this); } - } - return result; - } - private void switchUser(int userId) { - try { - WindowManagerGlobal.getWindowManagerService().lockNow(null); - ActivityManagerNative.getDefault().switchUser(userId); - } catch (RemoteException e) { - Log.e(TAG, "Couldn't switch user.", e); - } - } + TextView nameView = (TextView) convertView.findViewById(R.id.name); + UserAvatarView pictureView = (UserAvatarView) convertView.findViewById(R.id.picture); - private static class UserData { - final UserInfo userInfo; - final Bitmap userIcon; - final boolean isCurrent; + nameView.setText(getName(mContext, item)); + if (item.picture == null) { + pictureView.setDrawable(mContext.getDrawable(R.drawable.ic_account_circle_qs)); + } else { + pictureView.setBitmap(item.picture); + } + convertView.setActivated(item.isCurrent); + convertView.setTag(item); + return convertView; + } - UserData(UserInfo userInfo, Bitmap userIcon, boolean isCurrent) { - this.userInfo = userInfo; - this.userIcon = userIcon; - this.isCurrent = isCurrent; + @Override + public void onClick(View v) { + switchTo(((UserSwitcherController.UserRecord)v.getTag())); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 6d8b4001bd0d..b64dcbe2a699 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -24,7 +24,7 @@ public interface NetworkController { void setWifiEnabled(boolean enabled); public interface NetworkSignalChangedCallback { - void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, + void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId, boolean activityIn, boolean activityOut, String wifiSignalContentDescriptionId, String description); void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId, 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 2b089022b0ae..4fc2e0651eb4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -401,7 +401,7 @@ public class NetworkControllerImpl extends BroadcastReceiver boolean wifiOut = wifiEnabled && mWifiSsid != null && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT); - cb.onWifiSignalChanged(mWifiEnabled, mQSWifiIconId, wifiIn, wifiOut, + cb.onWifiSignalChanged(mWifiEnabled, mWifiConnected, mQSWifiIconId, wifiIn, wifiOut, mContentDescriptionWifi, wifiDesc); boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT @@ -573,9 +573,11 @@ public class NetworkControllerImpl extends BroadcastReceiver switch(mServiceState.getVoiceRegState()) { case ServiceState.STATE_POWER_OFF: retVal = false; + break; case ServiceState.STATE_OUT_OF_SERVICE: case ServiceState.STATE_EMERGENCY_ONLY: retVal = mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; + break; default: retVal = true; } @@ -597,8 +599,8 @@ public class NetworkControllerImpl extends BroadcastReceiver private final void updateTelephonySignalStrength() { Rlog.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService() + " ss=" + mSignalStrength); - if (false/*!hasService()*/) { - if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()"); + if (!hasService()) { + if (true/*CHATTY*/) Log.d(TAG, "updateTelephonySignalStrength: !hasService()"); mPhoneSignalIconId = R.drawable.stat_sys_signal_null; mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal; mDataSignalIconId = R.drawable.stat_sys_signal_null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java new file mode 100644 index 000000000000..ca71521319b8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java @@ -0,0 +1,84 @@ +/* + * 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.systemui.statusbar.policy; + +import android.app.AlarmClockInfo; +import android.app.AlarmManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.UserHandle; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; + +public class NextAlarmController extends BroadcastReceiver { + + private final ArrayList<NextAlarmChangeCallback> mChangeCallbacks = new ArrayList<>(); + + private AlarmManager mAlarmManager; + private AlarmClockInfo mNextAlarm; + + public NextAlarmController(Context context) { + mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_SWITCHED); + filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); + context.registerReceiver(this, filter); + updateNextAlarm(); + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("NextAlarmController state:"); + pw.print(" mNextAlarm="); pw.println(mNextAlarm); + } + + public void addStateChangedCallback(NextAlarmChangeCallback cb) { + mChangeCallbacks.add(cb); + cb.onNextAlarmChanged(mNextAlarm); + } + + public void removeStateChangedCallback(NextAlarmChangeCallback cb) { + mChangeCallbacks.remove(cb); + } + + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(Intent.ACTION_USER_SWITCHED) + || action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) { + updateNextAlarm(); + } + } + + private void updateNextAlarm() { + mNextAlarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT); + fireNextAlarmChanged(); + } + + private void fireNextAlarmChanged() { + int n = mChangeCallbacks.size(); + for (int i = 0; i < n; i++) { + mChangeCallbacks.get(i).onNextAlarmChanged(mNextAlarm); + } + } + + public interface NextAlarmChangeCallback { + void onNextAlarmChanged(AlarmClockInfo nextAlarm); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java new file mode 100644 index 000000000000..d405172ffa61 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java @@ -0,0 +1,127 @@ +/* + * 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.systemui.statusbar.policy; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; +import android.os.UserHandle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; + +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardActivityLauncher; +import com.android.systemui.statusbar.phone.KeyguardPreviewContainer; + +import java.util.List; + +/** + * Utility class to inflate previews for phone and camera affordance. + */ +public class PreviewInflater { + + private static final String TAG = "PreviewInflater"; + + private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout"; + + private Context mContext; + private LockPatternUtils mLockPatternUtils; + + public PreviewInflater(Context context, LockPatternUtils lockPatternUtils) { + mContext = context; + mLockPatternUtils = lockPatternUtils; + } + + public View inflatePreview(Intent intent) { + WidgetInfo info = getWidgetInfo(intent); + if (info == null) { + return null; + } + View v = inflateWidgetView(info); + if (v == null) { + return null; + } + KeyguardPreviewContainer container = new KeyguardPreviewContainer(mContext, null); + container.addView(v); + return container; + } + + private View inflateWidgetView(WidgetInfo widgetInfo) { + View widgetView = null; + try { + Context appContext = mContext.createPackageContext( + widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED); + LayoutInflater appInflater = (LayoutInflater) + appContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + appInflater = appInflater.cloneInContext(appContext); + widgetView = appInflater.inflate(widgetInfo.layoutId, null, false); + } catch (PackageManager.NameNotFoundException|RuntimeException e) { + Log.w(TAG, "Error creating widget view", e); + } + return widgetView; + } + + private WidgetInfo getWidgetInfo(Intent intent) { + WidgetInfo info = new WidgetInfo(); + PackageManager packageManager = mContext.getPackageManager(); + final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( + intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser()); + if (appList.size() == 0) { + return null; + } + ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, + PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA, + mLockPatternUtils.getCurrentUser()); + if (wouldLaunchResolverActivity(resolved, appList)) { + return null; + } + if (resolved == null || resolved.activityInfo == null) { + return null; + } + if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) { + return null; + } + int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT); + if (layoutId == 0) { + return null; + } + info.contextPackage = resolved.activityInfo.packageName; + info.layoutId = layoutId; + return info; + } + + private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) { + // If the list contains the above resolved activity, then it can't be + // ResolverActivity itself. + for (int i = 0; i < appList.size(); i++) { + ResolveInfo tmp = appList.get(i); + if (tmp.activityInfo.name.equals(resolved.activityInfo.name) + && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) { + return false; + } + } + return true; + } + + private static class WidgetInfo { + String contextPackage; + int layoutId; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 7bf2c3480b93..7c00c7fe074a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -123,7 +123,7 @@ public class UserSwitcherController { if (info.isGuest()) { guestRecord = new UserRecord(info, null /* picture */, true /* isGuest */, isCurrent); - } else if (!info.isManagedProfile()) { + } else if (info.supportsSwitchTo()) { Bitmap picture = bitmaps.get(info.id); if (picture == null) { picture = mUserManager.getUserIcon(info.id); @@ -303,6 +303,18 @@ public class UserSwitcherController { return item.info.name; } } + + public int getSwitchableUsers() { + int result = 0; + ArrayList<UserRecord> users = mController.mUsers; + int N = users.size(); + for (int i = 0; i < N; i++) { + if (users.get(i).info != null) { + result++; + } + } + return result; + } } public static final class UserRecord { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 9bcffd1b1735..9b819f2bc3e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -35,6 +35,7 @@ import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.SwipeHelper; import com.android.systemui.statusbar.ActivatableNotificationView; +import com.android.systemui.statusbar.DismissView; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.ExpandableView; import com.android.systemui.statusbar.SpeedBumpView; @@ -139,6 +140,8 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mExpandingNotification; private boolean mExpandedInThisMotion; private boolean mScrollingEnabled; + private DismissView mDismissView; + private boolean mDismissAllInProgress; /** * Was the scroller scrolled to the top when the down motion was observed? @@ -161,7 +164,7 @@ public class NotificationStackScrollLayout extends ViewGroup * motion. */ private int mMaxScrollAfterExpand; - private OnLongClickListener mLongClickListener; + private SwipeHelper.LongPressListener mLongPressListener; /** * Should in this touch motion only be scrolling allowed? It's true when the scroller was @@ -238,8 +241,8 @@ public class NotificationStackScrollLayout extends ViewGroup mOverflingDistance = configuration.getScaledOverflingDistance(); float densityScale = getResources().getDisplayMetrics().density; float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); - mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); - mSwipeHelper.setLongPressListener(mLongClickListener); + mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext()); + mSwipeHelper.setLongPressListener(mLongPressListener); mSidePaddings = context.getResources() .getDimensionPixelSize(R.dimen.notification_side_padding); @@ -467,9 +470,9 @@ public class NotificationStackScrollLayout extends ViewGroup return mBottomStackPeekSize; } - public void setLongPressListener(View.OnLongClickListener listener) { + public void setLongPressListener(SwipeHelper.LongPressListener listener) { mSwipeHelper.setLongPressListener(listener); - mLongClickListener = listener; + mLongPressListener = listener; } public void setScrollView(ViewGroup scrollView) { @@ -481,6 +484,9 @@ public class NotificationStackScrollLayout extends ViewGroup } public void onChildDismissed(View v) { + if (mDismissAllInProgress) { + return; + } if (DEBUG) Log.v(TAG, "onChildDismissed: " + v); final View veto = v.findViewById(R.id.veto); if (veto != null && veto.getVisibility() != View.GONE) { @@ -627,8 +633,9 @@ public class NotificationStackScrollLayout extends ViewGroup initView(getContext()); } - public void dismissRowAnimated(View child, int vel) { - mSwipeHelper.dismissChild(child, vel); + public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) { + child.setClipBounds(null); + mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration); } @Override @@ -1526,12 +1533,13 @@ public class NotificationStackScrollLayout extends ViewGroup * @param newIndex the new index */ public void changeViewPosition(View child, int newIndex) { - if (child != null && child.getParent() == this) { + int currentIndex = indexOfChild(child); + if (child != null && child.getParent() == this && currentIndex != newIndex) { mChangePositionInProgress = true; removeView(child); addView(child, newIndex); mChangePositionInProgress = false; - if (mIsExpanded && mAnimationsEnabled) { + if (mIsExpanded && mAnimationsEnabled && child.getVisibility() != View.GONE) { mChildrenChangingPositions.add(child); mNeedsAnimation = true; } @@ -1918,7 +1926,8 @@ public class NotificationStackScrollLayout extends ViewGroup } public void goToFullShade() { - updateSpeedBump(true); + updateSpeedBump(true /* visibility */); + mDismissView.setInvisible(); } public void cancelExpandHelper() { @@ -1962,6 +1971,54 @@ public class NotificationStackScrollLayout extends ViewGroup requestChildrenUpdate(); } + public void setDismissView(DismissView dismissView) { + mDismissView = dismissView; + addView(mDismissView); + } + + public void updateDismissView(boolean visible) { + int oldVisibility = mDismissView.willBeGone() ? GONE : mDismissView.getVisibility(); + int newVisibility = visible ? VISIBLE : GONE; + if (oldVisibility != newVisibility) { + if (oldVisibility == GONE) { + if (mDismissView.willBeGone()) { + mDismissView.cancelAnimation(); + } else { + mDismissView.setInvisible(); + mDismissView.setVisibility(newVisibility); + } + mDismissView.setWillBeGone(false); + updateContentHeight(); + } else { + mDismissView.setWillBeGone(true); + mDismissView.performVisibilityAnimation(false, new Runnable() { + @Override + public void run() { + mDismissView.setVisibility(GONE); + mDismissView.setWillBeGone(false); + updateContentHeight(); + } + }); + } + } + } + + public void setDismissAllInProgress(boolean dismissAllInProgress) { + mDismissAllInProgress = dismissAllInProgress; + } + + public boolean isDismissViewNotGone() { + return mDismissView.getVisibility() != View.GONE && !mDismissView.willBeGone(); + } + + public boolean isDismissViewVisible() { + return mDismissView.isVisible(); + } + + public int getDismissViewHeight() { + return mDismissView.getHeight() + mPaddingBetweenElementsNormal; + } + /** * A listener that is notified when some child locations might have changed. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java index f48739c708f9..7b90a3516efd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java @@ -21,6 +21,8 @@ import android.util.Log; import android.view.View; import android.view.ViewGroup; +import com.android.systemui.R; +import com.android.systemui.statusbar.DismissView; import com.android.systemui.statusbar.ExpandableView; import com.android.systemui.statusbar.SpeedBumpView; @@ -38,10 +40,13 @@ public class StackScrollState { private final ViewGroup mHostView; private Map<ExpandableView, ViewState> mStateMap; private final Rect mClipRect = new Rect(); + private final int mClearAllTopPadding; public StackScrollState(ViewGroup hostView) { mHostView = hostView; mStateMap = new HashMap<ExpandableView, ViewState>(); + mClearAllTopPadding = hostView.getContext().getResources().getDimensionPixelSize( + R.dimen.clear_all_padding_top); } public ViewGroup getHostView() { @@ -90,6 +95,7 @@ public class StackScrollState { if (!state.gone) { float alpha = child.getAlpha(); float yTranslation = child.getTranslationY(); + float xTranslation = child.getTranslationX(); float zTranslation = child.getTranslationZ(); float scale = child.getScaleX(); int height = child.getActualHeight(); @@ -99,7 +105,7 @@ public class StackScrollState { float newScale = state.scale; int newHeight = state.height; boolean becomesInvisible = newAlpha == 0.0f; - if (alpha != newAlpha) { + if (alpha != newAlpha && xTranslation == 0) { // apply layer type boolean becomesFullyVisible = newAlpha == 1.0f; boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible; @@ -167,6 +173,10 @@ public class StackScrollState { if(child instanceof SpeedBumpView) { float lineEnd = newYTranslation + newHeight / 2; performSpeedBumpAnimation(i, (SpeedBumpView) child, lineEnd); + } else if (child instanceof DismissView) { + DismissView dismissView = (DismissView) child; + boolean visible = state.topOverLap < mClearAllTopPadding; + dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone()); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index 0c8467569f3e..71524ec46498 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -159,7 +159,7 @@ public class StackStateAnimator { } // start alpha animation - if (alphaChanging) { + if (alphaChanging && child.getTranslationX() == 0) { startAlphaAnimation(child, viewState, delay); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index d0f61f0b31ce..a123bf7c1ada 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -95,6 +95,10 @@ public class TvStatusBar extends BaseStatusBar { public void setWindowState(int window, int state) { } + @Override // CommandQueue + public void buzzBeepBlinked() { + } + @Override protected WindowManager.LayoutParams getSearchLayoutParams( LayoutParams layoutParams) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java index 9ba9745ea757..149d09a0e400 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java @@ -58,6 +58,7 @@ import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import com.android.internal.R; +import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.ZenModeController; import java.io.FileDescriptor; @@ -89,6 +90,7 @@ public class VolumePanel extends Handler { private static final int TIMEOUT_DELAY = 3000; private static final int TIMEOUT_DELAY_SHORT = 1500; private static final int TIMEOUT_DELAY_COLLAPSED = 4500; + private static final int TIMEOUT_DELAY_SAFETY_WARNING = 5000; private static final int TIMEOUT_DELAY_EXPANDED = 10000; private static final int MSG_VOLUME_CHANGED = 0; @@ -238,42 +240,61 @@ public class VolumePanel extends Handler { private ToneGenerator mToneGenerators[]; private Vibrator mVibrator; - private static AlertDialog sConfirmSafeVolumeDialog; - private static Object sConfirmSafeVolumeLock = new Object(); + private static AlertDialog sSafetyWarning; + private static Object sSafetyWarningLock = new Object(); - private static class WarningDialogReceiver extends BroadcastReceiver - implements DialogInterface.OnDismissListener { + private static class SafetyWarning extends SystemUIDialog + implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { private final Context mContext; - private final Dialog mDialog; private final VolumePanel mVolumePanel; + private final AudioManager mAudioManager; - WarningDialogReceiver(Context context, Dialog dialog, VolumePanel volumePanel) { + SafetyWarning(Context context, VolumePanel volumePanel, AudioManager audioManager) { + super(context); mContext = context; - mDialog = dialog; mVolumePanel = volumePanel; + mAudioManager = audioManager; + + setMessage(mContext.getString(com.android.internal.R.string.safe_media_volume_warning)); + setButton(DialogInterface.BUTTON_POSITIVE, + mContext.getString(com.android.internal.R.string.yes), this); + setButton(DialogInterface.BUTTON_NEGATIVE, + mContext.getString(com.android.internal.R.string.no), (OnClickListener) null); + setOnDismissListener(this); + IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - context.registerReceiver(this, filter); + context.registerReceiver(mReceiver, filter); } @Override - public void onReceive(Context context, Intent intent) { - mDialog.cancel(); - cleanUp(); + public void onClick(DialogInterface dialog, int which) { + mAudioManager.disableSafeMediaVolume(); } @Override public void onDismiss(DialogInterface unused) { - mContext.unregisterReceiver(this); + mContext.unregisterReceiver(mReceiver); cleanUp(); } private void cleanUp() { - synchronized (sConfirmSafeVolumeLock) { - sConfirmSafeVolumeDialog = null; + synchronized (sSafetyWarningLock) { + sSafetyWarning = null; } mVolumePanel.forceTimeout(0); mVolumePanel.updateStates(); } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { + if (LOGD) Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS"); + cancel(); + cleanUp(); + } + } + }; } public VolumePanel(Context context, ZenModeController zenController) { @@ -305,7 +326,7 @@ public class VolumePanel extends Handler { @Override public boolean onTouchEvent(MotionEvent event) { if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE && - sConfirmSafeVolumeDialog == null) { + sSafetyWarning == null) { forceTimeout(0); return true; } @@ -371,7 +392,7 @@ public class VolumePanel extends Handler { final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds); mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds; - listenToRingerMode(); + registerReceiver(); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -389,7 +410,7 @@ public class VolumePanel extends Handler { pw.print(" isShowing()="); pw.println(isShowing()); pw.print(" mCallback="); pw.println(mCallback); pw.print(" sConfirmSafeVolumeDialog="); - pw.println(sConfirmSafeVolumeDialog != null ? "<not null>" : null); + pw.println(sSafetyWarning != null ? "<not null>" : null); pw.print(" mActiveStreamType="); pw.println(mActiveStreamType); pw.print(" mStreamControls="); if (mStreamControls == null) { @@ -441,9 +462,10 @@ public class VolumePanel extends Handler { updateStates(); } - private void listenToRingerMode() { + private void registerReceiver() { final IntentFilter filter = new IntentFilter(); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); + filter.addAction(Intent.ACTION_SCREEN_OFF); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -453,6 +475,10 @@ public class VolumePanel extends Handler { removeMessages(MSG_RINGER_MODE_CHANGED); sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED)); } + + if (Intent.ACTION_SCREEN_OFF.equals(action)) { + postDismiss(0); + } } }, filter); } @@ -635,7 +661,7 @@ public class VolumePanel extends Handler { sc.seekbarView.setEnabled(!fixedVolume); } else if (fixedVolume || (sc.streamType != mAudioManager.getMasterStreamType() && muted) || - (sConfirmSafeVolumeDialog != null)) { + (sSafetyWarning != null)) { sc.seekbarView.setEnabled(false); } else if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { sc.seekbarView.setEnabled(false); @@ -682,7 +708,8 @@ public class VolumePanel extends Handler { } private void updateTimeoutDelay() { - mTimeoutDelay = mActiveStreamType == AudioManager.STREAM_MUSIC ? TIMEOUT_DELAY_SHORT + mTimeoutDelay = sSafetyWarning != null ? TIMEOUT_DELAY_SAFETY_WARNING + : mActiveStreamType == AudioManager.STREAM_MUSIC ? TIMEOUT_DELAY_SHORT : mZenPanelExpanded ? TIMEOUT_DELAY_EXPANDED : isZenPanelVisible() ? TIMEOUT_DELAY_COLLAPSED : TIMEOUT_DELAY; @@ -1100,30 +1127,14 @@ public class VolumePanel extends Handler { } protected void onDisplaySafeVolumeWarning(int flags) { - if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || isShowing()) { - synchronized (sConfirmSafeVolumeLock) { - if (sConfirmSafeVolumeDialog != null) { + if ((flags & (AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_SHOW_UI_WARNINGS)) != 0 + || isShowing()) { + synchronized (sSafetyWarningLock) { + if (sSafetyWarning != null) { return; } - sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext) - .setMessage(com.android.internal.R.string.safe_media_volume_warning) - .setPositiveButton(com.android.internal.R.string.yes, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mAudioManager.disableSafeMediaVolume(); - } - }) - .setNegativeButton(com.android.internal.R.string.no, null) - .setIconAttribute(android.R.attr.alertDialogIcon) - .create(); - final WarningDialogReceiver warning = new WarningDialogReceiver(mContext, - sConfirmSafeVolumeDialog, this); - - sConfirmSafeVolumeDialog.setOnDismissListener(warning); - sConfirmSafeVolumeDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - sConfirmSafeVolumeDialog.show(); + sSafetyWarning = new SafetyWarning(mContext, this, mAudioManager); + sSafetyWarning.show(); } updateStates(); } @@ -1227,9 +1238,10 @@ public class VolumePanel extends Handler { mCallback.onVisible(false); } } - synchronized (sConfirmSafeVolumeLock) { - if (sConfirmSafeVolumeDialog != null) { - sConfirmSafeVolumeDialog.dismiss(); + synchronized (sSafetyWarningLock) { + if (sSafetyWarning != null) { + if (LOGD) Log.d(mTag, "SafetyWarning timeout"); + sSafetyWarning.dismiss(); } } break; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java index 9d050f9c369d..cc351f9ef1e4 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java @@ -195,7 +195,7 @@ public class VolumeUI extends SystemUI { @Override public void remoteVolumeChanged(ISessionController binder, int flags) throws RemoteException { - MediaController controller = new MediaController(binder); + MediaController controller = new MediaController(mContext, binder); mPanel.postRemoteVolumeChanged(controller, flags); } diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java index 5c8a8ef8cafb..57b0731c033c 100644 --- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java +++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java @@ -133,6 +133,14 @@ public class WallpaperCropActivity extends Activity { setCropViewTileSource(bitmapSource, true, false, onLoad); } + @Override + protected void onDestroy() { + if (mCropView != null) { + mCropView.destroy(); + } + super.onDestroy(); + } + public void setCropViewTileSource( final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled, final boolean moveToLeft, final Runnable postExecute) { diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java index a4c2ddd613f6..8fc4647da5f4 100644 --- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java +++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java @@ -293,7 +293,6 @@ public class ImmersiveModeConfirmation { @Override public boolean onTouchEvent(MotionEvent motion) { - Slog.v(TAG, "ClingWindowView.onTouchEvent"); return true; } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index e3c2203ac346..3e75947c2686 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -211,6 +211,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private float mElevation; + /** Whether window content should be clipped to the background outline. */ + private boolean mClipToOutline; + private int mFrameResource = 0; private int mTextColor = 0; @@ -1173,7 +1176,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mDecorContentParent != null) { final TypedValue outValue = new TypedValue(); final Theme baseTheme = context.getTheme(); - baseTheme.resolveAttribute(com.android.internal.R.attr.actionBarTheme, outValue, true); + baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true); Theme widgetTheme = null; if (outValue.resourceId != 0) { @@ -1181,10 +1184,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { widgetTheme.setTo(baseTheme); widgetTheme.applyStyle(outValue.resourceId, true); widgetTheme.resolveAttribute( - com.android.internal.R.attr.actionBarWidgetTheme, outValue, true); + R.attr.actionBarWidgetTheme, outValue, true); } else { baseTheme.resolveAttribute( - com.android.internal.R.attr.actionBarWidgetTheme, outValue, true); + R.attr.actionBarWidgetTheme, outValue, true); } if (outValue.resourceId != 0) { @@ -1305,6 +1308,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mBackgroundDrawable = drawable; if (mDecor != null) { mDecor.setWindowBackground(drawable); + mDecor.setClipToOutline(drawable != null && mClipToOutline); } } } @@ -1428,7 +1432,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) { updateProgressBars(value); } else if (featureId == FEATURE_CUSTOM_TITLE) { - FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container); + FrameLayout titleContainer = (FrameLayout) findViewById(R.id.title_container); if (titleContainer != null) { mLayoutInflater.inflate(value, titleContainer); } @@ -1546,7 +1550,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { final int features = getLocalFeatures(); - Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out); + Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.fade_out); anim.setDuration(1000); if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && spinnyProgressBar != null && @@ -2440,7 +2444,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { && getAttributes().height == WindowManager.LayoutParams.MATCH_PARENT) { mMenuBackground = getContext().getDrawable( - com.android.internal.R.drawable.menu_background); + R.drawable.menu_background); } if (mMenuBackground != null) { mMenuBackground.setBounds(drawingBounds.left, @@ -2606,7 +2610,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (isFloating()) { mActionModeView = new ActionBarContextView(mContext); mActionModePopup = new PopupWindow(mContext, null, - com.android.internal.R.attr.actionModePopupWindowStyle); + R.attr.actionModePopupWindowStyle); mActionModePopup.setWindowLayoutType( WindowManager.LayoutParams.TYPE_APPLICATION); mActionModePopup.setContentView(mActionModeView); @@ -2614,7 +2618,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { TypedValue heightValue = new TypedValue(); mContext.getTheme().resolveAttribute( - com.android.internal.R.attr.actionBarSize, heightValue, true); + R.attr.actionBarSize, heightValue, true); final int height = TypedValue.complexToDimensionPixelSize(heightValue.data, mContext.getResources().getDisplayMetrics()); mActionModeView.setContentHeight(height); @@ -2628,7 +2632,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { }; } else { ViewStub stub = (ViewStub) findViewById( - com.android.internal.R.id.action_mode_bar_stub); + R.id.action_mode_bar_stub); if (stub != null) { mActionModeView = (ActionBarContextView) stub.inflate(); } @@ -3093,14 +3097,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (false) { System.out.println("From style:"); String s = "Attrs:"; - for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) { - s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "=" + for (int i = 0; i < R.styleable.Window.length; i++) { + s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "=" + a.getString(i); } System.out.println(s); } - mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false); + mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false); int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR) & (~getForcedWindowFlags()); if (mIsFloating) { @@ -3110,78 +3114,78 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { + if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) { requestFeature(FEATURE_NO_TITLE); - } else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) { + } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) { // Don't allow an action bar if there is no title. requestFeature(FEATURE_ACTION_BAR); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) { + if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) { requestFeature(FEATURE_ACTION_BAR_OVERLAY); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionModeOverlay, false)) { + if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) { requestFeature(FEATURE_ACTION_MODE_OVERLAY); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowSwipeToDismiss, false)) { + if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) { requestFeature(FEATURE_SWIPE_TO_DISMISS); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) { + if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) { setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags())); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowTranslucentStatus, + if (a.getBoolean(R.styleable.Window_windowTranslucentStatus, false)) { setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS & (~getForcedWindowFlags())); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowTranslucentNavigation, + if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation, false)) { setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION & (~getForcedWindowFlags())); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowOverscan, false)) { + if (a.getBoolean(R.styleable.Window_windowOverscan, false)) { setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags())); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) { + if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags())); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowEnableSplitTouch, + if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch, getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB)) { setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags())); } - a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMajor, mMinWidthMajor); - a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMinor, mMinWidthMinor); - if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor)) { + a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor); + a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor); + if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) { if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue(); - a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor, + a.getValue(R.styleable.Window_windowFixedWidthMajor, mFixedWidthMajor); } - if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor)) { + if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) { if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue(); - a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor, + a.getValue(R.styleable.Window_windowFixedWidthMinor, mFixedWidthMinor); } - if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor)) { + if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) { if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue(); - a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor, + a.getValue(R.styleable.Window_windowFixedHeightMajor, mFixedHeightMajor); } - if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor)) { + if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) { if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue(); - a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor, + a.getValue(R.styleable.Window_windowFixedHeightMinor, mFixedHeightMinor); } - if (a.getBoolean(com.android.internal.R.styleable.Window_windowContentTransitions, false)) { + if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) { requestFeature(FEATURE_CONTENT_TRANSITIONS); } @@ -3190,9 +3194,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (windowService != null) { final Display display = windowService.getDefaultDisplay(); if (display.getDisplayId() == Display.DEFAULT_DISPLAY && - a.hasValue(com.android.internal.R.styleable.Window_windowOutsetBottom)) { + a.hasValue(R.styleable.Window_windowOutsetBottom)) { if (mOutsetBottom == null) mOutsetBottom = new TypedValue(); - a.getValue(com.android.internal.R.styleable.Window_windowOutsetBottom, + a.getValue(R.styleable.Window_windowOutsetBottom, mOutsetBottom); } } @@ -3203,7 +3207,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH; final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.L; final boolean targetHcNeedsOptions = context.getResources().getBoolean( - com.android.internal.R.bool.target_honeycomb_needs_options_menu); + R.bool.target_honeycomb_needs_options_menu); final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE); if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) { @@ -3216,7 +3220,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // therefore must know about visibility changes of those. if (!mIsFloating && ActivityManager.isHighEndGfx()) { if (!targetPreL && a.getBoolean( - com.android.internal.R.styleable.Window_windowDrawsSystemBarBackgrounds, + R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) { setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags()); @@ -3233,7 +3237,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { if (a.getBoolean( - com.android.internal.R.styleable.Window_windowCloseOnTouchOutside, + R.styleable.Window_windowCloseOnTouchOutside, false)) { setCloseOnTouchOutsideIfNotSet(true); } @@ -3243,11 +3247,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (!hasSoftInputMode()) { params.softInputMode = a.getInt( - com.android.internal.R.styleable.Window_windowSoftInputMode, + R.styleable.Window_windowSoftInputMode, params.softInputMode); } - if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled, + if (a.getBoolean(R.styleable.Window_backgroundDimEnabled, mIsFloating)) { /* All dialogs should have the window dimmed */ if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) { @@ -3261,7 +3265,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (params.windowAnimations == 0) { params.windowAnimations = a.getResourceId( - com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + R.styleable.Window_windowAnimationStyle, 0); } // The rest are only done if this window is not embedded; otherwise, @@ -3270,10 +3274,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mBackgroundDrawable == null) { if (mBackgroundResource == 0) { mBackgroundResource = a.getResourceId( - com.android.internal.R.styleable.Window_windowBackground, 0); + R.styleable.Window_windowBackground, 0); } if (mFrameResource == 0) { - mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0); + mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0); } if (false) { System.out.println("Background: " @@ -3281,8 +3285,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { + Integer.toHexString(mFrameResource)); } } - mElevation = a.getDimension(com.android.internal.R.styleable.Window_windowElevation, 0); - mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000); + mElevation = a.getDimension(R.styleable.Window_windowElevation, 0); + mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false); + mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT); } // Inflate the window decor. @@ -3291,15 +3296,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { int features = getLocalFeatures(); // System.out.println("Features: 0x" + Integer.toHexString(features)); if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) { - layoutResource = com.android.internal.R.layout.screen_swipe_dismiss; + layoutResource = R.layout.screen_swipe_dismiss; } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) { if (mIsFloating) { TypedValue res = new TypedValue(); getContext().getTheme().resolveAttribute( - com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true); + R.attr.dialogTitleIconsDecorLayout, res, true); layoutResource = res.resourceId; } else { - layoutResource = com.android.internal.R.layout.screen_title_icons; + layoutResource = R.layout.screen_title_icons; } // XXX Remove this once action bar supports these features. removeFeature(FEATURE_ACTION_BAR); @@ -3308,7 +3313,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { && (features & (1 << FEATURE_ACTION_BAR)) == 0) { // Special case for a window with only a progress bar (and title). // XXX Need to have a no-title version of embedded windows. - layoutResource = com.android.internal.R.layout.screen_progress; + layoutResource = R.layout.screen_progress; // System.out.println("Progress!"); } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) { // Special case for a window with a custom title. @@ -3316,10 +3321,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mIsFloating) { TypedValue res = new TypedValue(); getContext().getTheme().resolveAttribute( - com.android.internal.R.attr.dialogCustomTitleDecorLayout, res, true); + R.attr.dialogCustomTitleDecorLayout, res, true); layoutResource = res.resourceId; } else { - layoutResource = com.android.internal.R.layout.screen_custom_title; + layoutResource = R.layout.screen_custom_title; } // XXX Remove this once action bar supports these features. removeFeature(FEATURE_ACTION_BAR); @@ -3329,21 +3334,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mIsFloating) { TypedValue res = new TypedValue(); getContext().getTheme().resolveAttribute( - com.android.internal.R.attr.dialogTitleDecorLayout, res, true); + R.attr.dialogTitleDecorLayout, res, true); layoutResource = res.resourceId; } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) { layoutResource = a.getResourceId( - com.android.internal.R.styleable.Window_windowActionBarFullscreenDecorLayout, - com.android.internal.R.layout.screen_action_bar); + R.styleable.Window_windowActionBarFullscreenDecorLayout, + R.layout.screen_action_bar); } else { - layoutResource = com.android.internal.R.layout.screen_title; + layoutResource = R.layout.screen_title; } // System.out.println("Title!"); } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) { - layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode; + layoutResource = R.layout.screen_simple_overlay_action_mode; } else { // Embedded, so no decoration is needed. - layoutResource = com.android.internal.R.layout.screen_simple; + layoutResource = R.layout.screen_simple; // System.out.println("Simple!"); } @@ -3379,6 +3384,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } mDecor.setWindowBackground(background); + if (background != null) { + mDecor.setClipToOutline(mClipToOutline); + } + final Drawable frame; if (mFrameResource != 0) { frame = getContext().getDrawable(mFrameResource); @@ -3425,7 +3434,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mDecor.makeOptionalFitsSystemWindows(); final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById( - com.android.internal.R.id.decor_content_parent); + R.id.decor_content_parent); if (decorContentParent != null) { mDecorContentParent = decorContentParent; @@ -3469,12 +3478,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } }); } else { - mTitleView = (TextView)findViewById(com.android.internal.R.id.title); + mTitleView = (TextView)findViewById(R.id.title); if (mTitleView != null) { mTitleView.setLayoutDirection(mDecor.getLayoutDirection()); if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { View titleContainer = findViewById( - com.android.internal.R.id.title_container); + R.id.title_container); if (titleContainer != null) { titleContainer.setVisibility(View.GONE); } else { @@ -3494,7 +3503,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { if (mTransitionManager == null) { final int transitionRes = getWindowStyle().getResourceId( - com.android.internal.R.styleable.Window_windowContentTransitionManager, + R.styleable.Window_windowContentTransitionManager, 0); if (transitionRes != 0) { final TransitionInflater inflater = TransitionInflater.from(getContext()); @@ -3506,26 +3515,26 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } mEnterTransition = getTransition(mEnterTransition, - com.android.internal.R.styleable.Window_windowEnterTransition); + R.styleable.Window_windowEnterTransition); mExitTransition = getTransition(mExitTransition, - com.android.internal.R.styleable.Window_windowExitTransition); + R.styleable.Window_windowExitTransition); mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, - com.android.internal.R.styleable.Window_windowSharedElementEnterTransition); + R.styleable.Window_windowSharedElementEnterTransition); mSharedElementExitTransition = getTransition(mSharedElementExitTransition, - com.android.internal.R.styleable.Window_windowSharedElementExitTransition); + R.styleable.Window_windowSharedElementExitTransition); if (mAllowEnterTransitionOverlap == null) { mAllowEnterTransitionOverlap = getWindowStyle().getBoolean( - com.android.internal.R.styleable. + R.styleable. Window_windowAllowEnterTransitionOverlap, true); } if (mAllowExitTransitionOverlap == null) { mAllowExitTransitionOverlap = getWindowStyle().getBoolean( - com.android.internal.R.styleable. + R.styleable. Window_windowAllowExitTransitionOverlap, true); } if (mBackgroundFadeDurationMillis < 0) { mBackgroundFadeDurationMillis = getWindowStyle().getInteger( - com.android.internal.R.styleable. + R.styleable. Window_windowTransitionBackgroundFadeDuration, DEFAULT_BACKGROUND_FADE_DURATION_MS); } @@ -3539,7 +3548,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } int transitionId = getWindowStyle().getResourceId(id, -1); Transition transition = null; - if (transitionId != -1 && transitionId != com.android.internal.R.transition.no_transition) { + if (transitionId != -1 && transitionId != R.transition.no_transition) { TransitionInflater inflater = TransitionInflater.from(getContext()); transition = inflater.inflateTransition(transitionId); } @@ -3713,7 +3722,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mContentParent == null) { installDecor(); } - return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon)); + return (mLeftIconView = (ImageView)findViewById(R.id.left_icon)); } @Override @@ -3731,7 +3740,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mContentParent == null && shouldInstallDecor) { installDecor(); } - mCircularProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_circular); + mCircularProgressBar = (ProgressBar) findViewById(R.id.progress_circular); if (mCircularProgressBar != null) { mCircularProgressBar.setVisibility(View.INVISIBLE); } @@ -3745,7 +3754,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mContentParent == null && shouldInstallDecor) { installDecor(); } - mHorizontalProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_horizontal); + mHorizontalProgressBar = (ProgressBar) findViewById(R.id.progress_horizontal); if (mHorizontalProgressBar != null) { mHorizontalProgressBar.setVisibility(View.INVISIBLE); } @@ -3759,12 +3768,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mContentParent == null) { installDecor(); } - return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon)); + return (mRightIconView = (ImageView)findViewById(R.id.right_icon)); } private void registerSwipeCallbacks() { SwipeDismissLayout swipeDismiss = - (SwipeDismissLayout) findViewById(com.android.internal.R.id.content); + (SwipeDismissLayout) findViewById(R.id.content); swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() { @Override public void onDismissed(SwipeDismissLayout layout) { @@ -3882,7 +3891,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private boolean isTranslucent() { TypedArray a = getWindowStyle(); return a.getBoolean(a.getResourceId( - com.android.internal.R.styleable.Window_windowIsTranslucent, 0), false); + R.styleable.Window_windowIsTranslucent, 0), false); } @Override @@ -4100,18 +4109,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } void setStyle(Context context) { - TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); + TypedArray a = context.obtainStyledAttributes(R.styleable.Theme); background = a.getResourceId( - com.android.internal.R.styleable.Theme_panelBackground, 0); + R.styleable.Theme_panelBackground, 0); fullBackground = a.getResourceId( - com.android.internal.R.styleable.Theme_panelFullBackground, 0); + R.styleable.Theme_panelFullBackground, 0); windowAnimations = a.getResourceId( - com.android.internal.R.styleable.Theme_windowAnimationStyle, 0); + R.styleable.Theme_windowAnimationStyle, 0); isCompact = a.getBoolean( - com.android.internal.R.styleable.Theme_panelMenuIsCompact, false); + R.styleable.Theme_panelMenuIsCompact, false); listPresenterTheme = a.getResourceId( - com.android.internal.R.styleable.Theme_panelMenuListTheme, - com.android.internal.R.style.Theme_ExpandedMenu); + R.styleable.Theme_panelMenuListTheme, + R.style.Theme_ExpandedMenu); a.recycle(); } @@ -4138,9 +4147,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (listMenuPresenter == null) { listMenuPresenter = new ListMenuPresenter( - com.android.internal.R.layout.list_menu_item_layout, listPresenterTheme); + R.layout.list_menu_item_layout, listPresenterTheme); listMenuPresenter.setCallback(cb); - listMenuPresenter.setId(com.android.internal.R.id.list_menu_presenter); + listMenuPresenter.setId(R.id.list_menu_presenter); menu.addMenuPresenter(listMenuPresenter); } @@ -4159,7 +4168,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (iconMenuPresenter == null) { iconMenuPresenter = new IconMenuPresenter(context); iconMenuPresenter.setCallback(cb); - iconMenuPresenter.setId(com.android.internal.R.id.icon_menu_presenter); + iconMenuPresenter.setId(R.id.icon_menu_presenter); menu.addMenuPresenter(iconMenuPresenter); } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 44a53448ccb7..324f5365b174 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -5401,7 +5401,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0; - if (!always && (hapticsDisabled || mKeyguardDelegate.isShowingAndNotOccluded())) { + if (hapticsDisabled && !always) { return false; } long[] pattern = null; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 07bb71384175..b1f19540060c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -62,7 +62,6 @@ import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; -import android.util.LongArray; import android.util.Pools.Pool; import android.util.Pools.SimplePool; import android.util.Slog; @@ -114,8 +113,6 @@ import java.util.concurrent.CopyOnWriteArrayList; * accessed only by the system. The task of this service is to be a centralized * event dispatch for {@link AccessibilityEvent}s generated across all processes * on the device. Events are dispatched to {@link AccessibilityService}s. - * - * @hide */ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @@ -155,13 +152,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final Object mLock = new Object(); private final Pool<PendingEvent> mPendingEventPool = - new SimplePool<PendingEvent>(MAX_POOL_SIZE); + new SimplePool<>(MAX_POOL_SIZE); private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = - new ArrayList<AccessibilityServiceInfo>(); + new ArrayList<>(); private final Rect mTempRect = new Rect(); @@ -183,27 +180,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private boolean mHasInputFilter; - private final Set<ComponentName> mTempComponentNameSet = new HashSet<ComponentName>(); + private final Set<ComponentName> mTempComponentNameSet = new HashSet<>(); private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList = - new ArrayList<AccessibilityServiceInfo>(); + new ArrayList<>(); private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients = - new RemoteCallbackList<IAccessibilityManagerClient>(); + new RemoteCallbackList<>(); private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections = - new SparseArray<AccessibilityConnectionWrapper>(); + new SparseArray<>(); - private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>(); + private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>(); - private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); + private final SparseArray<UserState> mUserStates = new SparseArray<>(); private final UserManager mUserManager; private int mCurrentUserId = UserHandle.USER_OWNER; - private final LongArray mTempLongArray = new LongArray(); - //TODO: Remove this hack private boolean mInitialized; @@ -439,10 +434,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // to clients as being installed - it really is not. UserState userState = getUserStateLocked(resolvedUserId); if (userState.mUiAutomationService != null) { - List<AccessibilityServiceInfo> installedServices = - new ArrayList<AccessibilityServiceInfo>(); + List<AccessibilityServiceInfo> installedServices = new ArrayList<>(); installedServices.addAll(userState.mInstalledServices); - installedServices.remove(userState.mUiAutomationService); + installedServices.remove(userState.mUiAutomationService.mAccessibilityServiceInfo); return installedServices; } return userState.mInstalledServices; @@ -655,7 +649,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // Automation service is not bound, so pretend it died to perform clean up. if (userState.mUiAutomationService != null && serviceClient != null - && userState.mUiAutomationService != null && userState.mUiAutomationService.mServiceInterface != null && userState.mUiAutomationService.mServiceInterface.asBinder() == serviceClient.asBinder()) { @@ -907,16 +900,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - private void notifyWindowsChangedLocked(List<AccessibilityWindowInfo> windows) { - UserState state = getCurrentUserStateLocked(); - for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { - Service service = state.mBoundServices.get(i); - if (mSecurityPolicy.canRetrieveWindowsLocked(service)) { - service.notifyWindowsChangedLocked(windows); - } - } - } - /** * Removes an AccessibilityInteractionConnection. * @@ -961,10 +944,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { try { accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo); - } catch (XmlPullParserException xppe) { + } catch (XmlPullParserException | IOException xppe) { Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe); - } catch (IOException ioe) { - Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe); } } @@ -1035,7 +1016,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // An out of bounds exception can happen if services are going away // as the for loop is running. If that happens, just bail because // there are no more services to notify. - return; } } @@ -1053,7 +1033,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * Removes a service. * * @param service The service. - * @return True if the service was removed, false otherwise. */ private void removeServiceLocked(Service service, UserState userState) { userState.mBoundServices.remove(service); @@ -1093,7 +1072,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } Set<String> packageNames = service.mPackageNames; - CharSequence packageName = event.getPackageName(); + String packageName = (event.getPackageName() != null) + ? event.getPackageName().toString() : null; if (packageNames.isEmpty() || packageNames.contains(packageName)) { int feedbackType = service.mFeedbackType; @@ -1386,8 +1366,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (mWindowsForAccessibilityCallback != null) { mWindowsForAccessibilityCallback = null; - mWindowManagerService.setWindowsForAccessibilityCallback( - mWindowsForAccessibilityCallback); + mWindowManagerService.setWindowsForAccessibilityCallback(null); } } @@ -1437,8 +1416,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } private boolean readConfigurationForUserStateLocked(UserState userState) { - boolean somthingChanged = false; - somthingChanged |= readAccessibilityEnabledSettingLocked(userState); + boolean somthingChanged = readAccessibilityEnabledSettingLocked(userState); somthingChanged |= readInstalledAccessibilityServiceLocked(userState); somthingChanged |= readEnabledAccessibilityServicesLocked(userState); somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState); @@ -1868,7 +1846,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { int mFeedbackType; - Set<String> mPackageNames = new HashSet<String>(); + Set<String> mPackageNames = new HashSet<>(); boolean mIsDefault; @@ -1890,20 +1868,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { boolean mIsAutomation; - final Rect mTempBounds1 = new Rect(); - - final Rect mTempBounds2 = new Rect(); - final ResolveInfo mResolveInfo; // the events pending events to be dispatched to this service final SparseArray<AccessibilityEvent> mPendingEvents = - new SparseArray<AccessibilityEvent>(); + new SparseArray<>(); final KeyEventDispatcher mKeyEventDispatcher = new KeyEventDispatcher(); final SparseArray<AccessibilityWindowInfo> mIntrospectedWindows = - new SparseArray<AccessibilityWindowInfo>(); + new SparseArray<>(); boolean mWasConnectedAndDied; @@ -2106,7 +2080,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (!permissionGranted) { return null; } - List<AccessibilityWindowInfo> windows = new ArrayList<AccessibilityWindowInfo>(); + List<AccessibilityWindowInfo> windows = new ArrayList<>(); final int windowCount = mSecurityPolicy.mWindows.size(); for (int i = 0; i < windowCount; i++) { AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i); @@ -2646,51 +2620,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - public void notifyWindowsChangedLocked(List<AccessibilityWindowInfo> windows) { - LongArray changedWindows = mTempLongArray; - changedWindows.clear(); - - // Figure out which windows the service cares about changed. - final int windowCount = windows.size(); - for (int i = 0; i < windowCount; i++) { - AccessibilityWindowInfo newState = windows.get(i); - final int windowId = newState.getId(); - AccessibilityWindowInfo oldState = mIntrospectedWindows.get(windowId); - if (oldState != null && oldState.changed(newState)) { - oldState.recycle(); - mIntrospectedWindows.put(newState.getId(), - AccessibilityWindowInfo.obtain(newState)); - changedWindows.add(windowId); - } - } - - // Figure out which windows the service cares about went away. - final int introspectedWindowCount = mIntrospectedWindows.size(); - for (int i = introspectedWindowCount - 1; i >= 0; i--) { - AccessibilityWindowInfo window = mIntrospectedWindows.valueAt(i); - if (changedWindows.indexOf(window.getId()) < 0 && !windows.contains(window)) { - changedWindows.add(window.getId()); - mIntrospectedWindows.removeAt(i); - window.recycle(); - } - } - - int[] windowIds = null; - - final int changedWindowCount = changedWindows.size(); - if (changedWindowCount > 0) { - windowIds = new int[changedWindowCount]; - for (int i = 0; i < changedWindowCount; i++) { - // Cast is fine as we use long array to cache ints. - windowIds[i] = (int) changedWindows.get(i); - } - changedWindows.clear(); - } - - mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_WINDOWS_CHANGED, - windowIds).sendToTarget(); - } - private void notifyGestureInternal(int gestureId) { final IAccessibilityServiceClient listener; synchronized (mLock) { @@ -2725,20 +2654,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - private void notifyWindowsChangedInternal(int[] windowIds) { - final IAccessibilityServiceClient listener; - synchronized (mLock) { - listener = mServiceInterface; - } - if (listener != null) { - try { - listener.onWindowsChanged(windowIds); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error during sending windows to: " + mService, re); - } - } - } - private void sendDownAndUpKeyEvents(int keyCode) { final long token = Binder.clearCallingIdentity(); @@ -2844,7 +2759,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public static final int MSG_ON_KEY_EVENT = 2; public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 3; public static final int MSG_ON_KEY_EVENT_TIMEOUT = 4; - public static final int MSG_ON_WINDOWS_CHANGED = 5; public InvocationHandler(Looper looper) { super(looper, null, true); @@ -2874,11 +2788,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { setOnKeyEventResult(false, eventState.sequence); } break; - case MSG_ON_WINDOWS_CHANGED: { - final int[] windowIds = (int[]) message.obj; - notifyWindowsChangedInternal(windowIds); - } break; - default: { throw new IllegalArgumentException("Unknown message: " + type); } @@ -3028,14 +2937,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public void onWindowsForAccessibilityChanged(List<WindowInfo> windows) { synchronized (mLock) { - List<WindowInfo> receivedWindows = (List<WindowInfo>) windows; - // Populate the windows to report. - List<AccessibilityWindowInfo> reportedWindows = - new ArrayList<AccessibilityWindowInfo>(); - final int receivedWindowCount = receivedWindows.size(); + List<AccessibilityWindowInfo> reportedWindows = new ArrayList<>(); + final int receivedWindowCount = windows.size(); for (int i = 0; i < receivedWindowCount; i++) { - WindowInfo receivedWindow = receivedWindows.get(i); + WindowInfo receivedWindow = windows.get(i); AccessibilityWindowInfo reportedWindow = populateReportedWindow( receivedWindow); if (reportedWindow != null) { @@ -3224,8 +3130,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; - public final List<AccessibilityWindowInfo> mWindows = - new ArrayList<AccessibilityWindowInfo>(); + public final List<AccessibilityWindowInfo> mWindows = new ArrayList<>(); public int mActiveWindowId = INVALID_WINDOW_ID; public int mFocusedWindowId = INVALID_WINDOW_ID; @@ -3265,7 +3170,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START: case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: - case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: { + case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: + // Also windows changing should always be anounced. + case AccessibilityEvent.TYPE_WINDOWS_CHANGED: { return true; } // All events for changes in window content should be @@ -3327,7 +3234,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - notifyWindowsChangedLocked(mWindows); + notifyWindowsChanged(); // If we are delaying a window state change event as the window // source was showing when it was fired, now is the time to send. @@ -3452,10 +3359,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityWindowInfo window = mWindows.get(i); window.setActive(window.getId() == windowId); } - notifyWindowsChangedLocked(mWindows); + notifyWindowsChanged(); } } + private void notifyWindowsChanged() { + // Let the client know the windows changed. + AccessibilityEvent event = AccessibilityEvent.obtain( + AccessibilityEvent.TYPE_WINDOWS_CHANGED); + event.setEventTime(SystemClock.uptimeMillis()); + sendAccessibilityEvent(event, mCurrentUserId); + } + public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) { return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId); } @@ -3568,30 +3483,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // Non-transient state. public final RemoteCallbackList<IAccessibilityManagerClient> mClients = - new RemoteCallbackList<IAccessibilityManagerClient>(); + new RemoteCallbackList<>(); public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections = - new SparseArray<AccessibilityConnectionWrapper>(); + new SparseArray<>(); - public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>(); + public final SparseArray<IBinder> mWindowTokens = new SparseArray<>(); // Transient state. public final CopyOnWriteArrayList<Service> mBoundServices = - new CopyOnWriteArrayList<Service>(); + new CopyOnWriteArrayList<>(); public final Map<ComponentName, Service> mComponentNameToServiceMap = - new HashMap<ComponentName, Service>(); + new HashMap<>(); public final List<AccessibilityServiceInfo> mInstalledServices = - new ArrayList<AccessibilityServiceInfo>(); + new ArrayList<>(); - public final Set<ComponentName> mBindingServices = new HashSet<ComponentName>(); + public final Set<ComponentName> mBindingServices = new HashSet<>(); - public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>(); + public final Set<ComponentName> mEnabledServices = new HashSet<>(); public final Set<ComponentName> mTouchExplorationGrantedServices = - new HashSet<ComponentName>(); + new HashSet<>(); public int mHandledFeedbackTypes = 0; diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 56b8c928b8f4..291d366a75a4 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -34,6 +34,7 @@ import android.app.backup.IBackupManager; import android.app.backup.IFullBackupRestoreObserver; import android.app.backup.IRestoreObserver; import android.app.backup.IRestoreSession; +import android.app.job.JobParameters; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -78,6 +79,7 @@ import android.os.storage.IMountService; import android.provider.Settings; import android.system.ErrnoException; import android.system.Os; +import android.util.AtomicFile; import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -119,6 +121,7 @@ import java.security.spec.KeySpec; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -154,6 +157,7 @@ public class BackupManagerService extends IBackupManager.Stub { private static final String TAG = "BackupManagerService"; private static final boolean DEBUG = true; private static final boolean MORE_DEBUG = false; + private static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true; // System-private key used for backing up an app's widget state. Must // begin with U+FFxx by convention (we reserve all keys starting @@ -239,7 +243,10 @@ public class BackupManagerService extends IBackupManager.Stub { // order to give them time to enter the backup password. static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; - private Context mContext; + // How long between attempts to perform a full-data backup of any given app + static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day + + Context mContext; private PackageManager mPackageManager; IPackageManager mPackageManagerBinder; private IActivityManager mActivityManager; @@ -313,17 +320,32 @@ public class BackupManagerService extends IBackupManager.Stub { // Watch the device provisioning operation during setup ContentObserver mProvisionedObserver; + static BackupManagerService sInstance; + static BackupManagerService getInstance() { + // Always constructed during system bringup, so no need to lazy-init + return sInstance; + } + public static final class Lifecycle extends SystemService { - private final BackupManagerService mService; public Lifecycle(Context context) { super(context); - mService = new BackupManagerService(context); + sInstance = new BackupManagerService(context); } @Override public void onStart() { - publishBinderService(Context.BACKUP_SERVICE, mService); + publishBinderService(Context.BACKUP_SERVICE, sInstance); + } + + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + ContentResolver r = sInstance.mContext.getContentResolver(); + boolean areEnabled = Settings.Secure.getInt(r, + Settings.Secure.BACKUP_ENABLED, 0) != 0; + sInstance.setBackupEnabled(areEnabled); + } } } @@ -542,6 +564,30 @@ public class BackupManagerService extends IBackupManager.Stub { static final String INIT_SENTINEL_FILE_NAME = "_need_init_"; HashSet<String> mPendingInits = new HashSet<String>(); // transport names + // Round-robin queue for scheduling full backup passes + static final int SCHEDULE_FILE_VERSION = 1; // current version of the schedule file + class FullBackupEntry implements Comparable<FullBackupEntry> { + String packageName; + long lastBackup; + + FullBackupEntry(String pkg, long when) { + packageName = pkg; + lastBackup = when; + } + + @Override + public int compareTo(FullBackupEntry other) { + if (lastBackup < other.lastBackup) return -1; + else if (lastBackup > other.lastBackup) return 1; + else return 0; + } + } + + File mFullBackupScheduleFile; + // If we're running a schedule-driven full backup, this is the task instance doing it + PerformFullTransportBackupTask mRunningFullBackupTask; // inside mQueueLock + ArrayList<FullBackupEntry> mFullBackupQueue; // inside mQueueLock + // Utility: build a new random integer token int generateToken() { int token; @@ -573,6 +619,17 @@ public class BackupManagerService extends IBackupManager.Stub { return true; } + /* does *not* check overall backup eligibility policy! */ + public static boolean appGetsFullBackup(PackageInfo pkg) { + if (pkg.applicationInfo.backupAgentName != null) { + // If it has an agent, it gets full backups only if it says so + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0; + } + + // No agent means we do full backups for it + return true; + } + // ----- Asynchronous backup/restore handler thread ----- private class BackupHandler extends Handler { @@ -892,8 +949,6 @@ public class BackupManagerService extends IBackupManager.Stub { // Set up our bookkeeping final ContentResolver resolver = context.getContentResolver(); - boolean areEnabled = Settings.Secure.getInt(resolver, - Settings.Secure.BACKUP_ENABLED, 0) != 0; mProvisioned = Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0; mAutoRestore = Settings.Secure.getInt(resolver, @@ -987,6 +1042,7 @@ public class BackupManagerService extends IBackupManager.Stub { mJournal = null; // will be created on first use // Set up the various sorts of package tracking we do + mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); initPackageTracking(); // Build our mapping of uid to backup client services. This implicitly @@ -1050,9 +1106,6 @@ public class BackupManagerService extends IBackupManager.Stub { // Power management mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"); - - // Start the backup passes going - setBackupEnabled(areEnabled); } private class RunBackupReceiver extends BroadcastReceiver { @@ -1192,6 +1245,9 @@ public class BackupManagerService extends IBackupManager.Stub { } } + // Resume the full-data backup queue + mFullBackupQueue = readFullBackupSchedule(); + // Register for broadcasts about package install, etc., so we can // update the provider list. IntentFilter filter = new IntentFilter(); @@ -1206,6 +1262,96 @@ public class BackupManagerService extends IBackupManager.Stub { mContext.registerReceiver(mBroadcastReceiver, sdFilter); } + private ArrayList<FullBackupEntry> readFullBackupSchedule() { + ArrayList<FullBackupEntry> schedule = null; + synchronized (mQueueLock) { + if (mFullBackupScheduleFile.exists()) { + try { + FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile); + BufferedInputStream bufStream = new BufferedInputStream(fstream); + DataInputStream in = new DataInputStream(bufStream); + + int version = in.readInt(); + if (version != SCHEDULE_FILE_VERSION) { + Slog.e(TAG, "Unknown backup schedule version " + version); + return null; + } + + int N = in.readInt(); + schedule = new ArrayList<FullBackupEntry>(N); + for (int i = 0; i < N; i++) { + String pkgName = in.readUTF(); + long lastBackup = in.readLong(); + schedule.add(new FullBackupEntry(pkgName, lastBackup)); + } + Collections.sort(schedule); + } catch (Exception e) { + Slog.e(TAG, "Unable to read backup schedule", e); + mFullBackupScheduleFile.delete(); + schedule = null; + } + } + + if (schedule == null) { + // no prior queue record, or unable to read it. Set up the queue + // from scratch. + List<PackageInfo> apps = + PackageManagerBackupAgent.getStorableApplications(mPackageManager); + final int N = apps.size(); + schedule = new ArrayList<FullBackupEntry>(N); + for (int i = 0; i < N; i++) { + PackageInfo info = apps.get(i); + if (appGetsFullBackup(info)) { + schedule.add(new FullBackupEntry(info.packageName, 0)); + } + } + writeFullBackupScheduleAsync(); + } + } + return schedule; + } + + Runnable mFullBackupScheduleWriter = new Runnable() { + @Override public void run() { + synchronized (mQueueLock) { + try { + ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096); + DataOutputStream bufOut = new DataOutputStream(bufStream); + bufOut.writeInt(SCHEDULE_FILE_VERSION); + + // version 1: + // + // [int] # of packages in the queue = N + // N * { + // [utf8] package name + // [long] last backup time for this package + // } + int N = mFullBackupQueue.size(); + bufOut.writeInt(N); + + for (int i = 0; i < N; i++) { + FullBackupEntry entry = mFullBackupQueue.get(i); + bufOut.writeUTF(entry.packageName); + bufOut.writeLong(entry.lastBackup); + } + bufOut.flush(); + + AtomicFile af = new AtomicFile(mFullBackupScheduleFile); + FileOutputStream out = af.startWrite(); + out.write(bufStream.toByteArray()); + af.finishWrite(out); + } catch (Exception e) { + Slog.e(TAG, "Unable to write backup schedule!", e); + } + } + } + }; + + private void writeFullBackupScheduleAsync() { + mBackupHandler.removeCallbacks(mFullBackupScheduleWriter); + mBackupHandler.post(mFullBackupScheduleWriter); + } + private void parseLeftoverJournals() { for (File f : mJournalDir.listFiles()) { if (mJournal == null || f.compareTo(mJournal) != 0) { @@ -1633,6 +1779,22 @@ public class BackupManagerService extends IBackupManager.Stub { } addPackageParticipantsLocked(pkgList); } + // If they're full-backup candidates, add them there instead + for (String packageName : pkgList) { + try { + PackageInfo app = mPackageManager.getPackageInfo(packageName, 0); + long now = System.currentTimeMillis(); + if (appGetsFullBackup(app)) { + enqueueFullBackup(packageName, now); + scheduleNextFullBackupJob(); + } + } catch (NameNotFoundException e) { + // doesn't really exist; ignore it + if (DEBUG) { + Slog.i(TAG, "Can't resolve new app " + packageName); + } + } + } } else { if (replacing) { // The package is being updated. We'll receive a PACKAGE_ADDED shortly. @@ -3437,12 +3599,19 @@ public class BackupManagerService extends IBackupManager.Stub { class PerformFullTransportBackupTask extends FullBackupTask { static final String TAG = "PFTBT"; ArrayList<PackageInfo> mPackages; + boolean mUpdateSchedule; AtomicBoolean mLatch; + AtomicBoolean mKeepRunning; // signal from job scheduler + FullBackupJob mJob; // if a scheduled job needs to be finished afterwards PerformFullTransportBackupTask(IFullBackupRestoreObserver observer, - String[] whichPackages, AtomicBoolean latch) { + String[] whichPackages, boolean updateSchedule, + FullBackupJob runningJob, AtomicBoolean latch) { super(observer); + mUpdateSchedule = updateSchedule; mLatch = latch; + mKeepRunning = new AtomicBoolean(true); + mJob = runningJob; mPackages = new ArrayList<PackageInfo>(whichPackages.length); for (String pkg : whichPackages) { @@ -3474,119 +3643,164 @@ public class BackupManagerService extends IBackupManager.Stub { } } + public void setRunning(boolean running) { + mKeepRunning.set(running); + } + @Override public void run() { - IBackupTransport transport = getTransport(mCurrentTransport); - if (transport == null) { - Slog.w(TAG, "Transport not present; full data backup not performed"); - return; - } - // data from the app, passed to us for bridging to the transport ParcelFileDescriptor[] enginePipes = null; // Pipe through which we write data to the transport ParcelFileDescriptor[] transportPipes = null; + PackageInfo currentPackage; + try { - // Set up to send data to the transport - if (transport != null) { - for (PackageInfo target : mPackages) { - if (DEBUG) { - Slog.i(TAG, "Initiating full-data transport backup of " - + target.packageName); - } - transportPipes = ParcelFileDescriptor.createPipe(); + IBackupTransport transport = getTransport(mCurrentTransport); + if (transport == null) { + Slog.w(TAG, "Transport not present; full data backup not performed"); + return; + } - // Tell the transport the data's coming - int result = transport.performFullBackup(target, transportPipes[0]); - if (result == BackupTransport.TRANSPORT_OK) { - // The transport has its own copy of the read end of the pipe, - // so close ours now - transportPipes[0].close(); - transportPipes[0] = null; - - // Now set up the backup engine / data source end of things - enginePipes = ParcelFileDescriptor.createPipe(); - AtomicBoolean runnerLatch = new AtomicBoolean(false); - SinglePackageBackupRunner backupRunner = - new SinglePackageBackupRunner(enginePipes[1], target, - runnerLatch); - // The runner dup'd the pipe half, so we close it here - enginePipes[1].close(); - enginePipes[1] = null; - - // Spin off the runner to fetch the app's data and pipe it - // into the engine pipes - (new Thread(backupRunner, "package-backup-bridge")).start(); - - // Read data off the engine pipe and pass it to the transport - // pipe until we hit EOD on the input stream. - FileInputStream in = new FileInputStream( - enginePipes[0].getFileDescriptor()); - FileOutputStream out = new FileOutputStream( - transportPipes[1].getFileDescriptor()); - byte[] buffer = new byte[8192]; - int nRead = 0; - do { - nRead = in.read(buffer); - if (nRead > 0) { - out.write(buffer, 0, nRead); - result = transport.sendBackupData(nRead); + // Set up to send data to the transport + final int N = mPackages.size(); + for (int i = 0; i < N; i++) { + currentPackage = mPackages.get(i); + if (DEBUG) { + Slog.i(TAG, "Initiating full-data transport backup of " + + currentPackage.packageName); + } + transportPipes = ParcelFileDescriptor.createPipe(); + + // Tell the transport the data's coming + int result = transport.performFullBackup(currentPackage, + transportPipes[0]); + if (result == BackupTransport.TRANSPORT_OK) { + // The transport has its own copy of the read end of the pipe, + // so close ours now + transportPipes[0].close(); + transportPipes[0] = null; + + // Now set up the backup engine / data source end of things + enginePipes = ParcelFileDescriptor.createPipe(); + AtomicBoolean runnerLatch = new AtomicBoolean(false); + SinglePackageBackupRunner backupRunner = + new SinglePackageBackupRunner(enginePipes[1], currentPackage, + runnerLatch); + // The runner dup'd the pipe half, so we close it here + enginePipes[1].close(); + enginePipes[1] = null; + + // Spin off the runner to fetch the app's data and pipe it + // into the engine pipes + (new Thread(backupRunner, "package-backup-bridge")).start(); + + // Read data off the engine pipe and pass it to the transport + // pipe until we hit EOD on the input stream. + FileInputStream in = new FileInputStream( + enginePipes[0].getFileDescriptor()); + FileOutputStream out = new FileOutputStream( + transportPipes[1].getFileDescriptor()); + byte[] buffer = new byte[8192]; + int nRead = 0; + do { + if (!mKeepRunning.get()) { + if (DEBUG_SCHEDULING) { + Slog.i(TAG, "Full backup task told to stop"); } - } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK); + break; + } + nRead = in.read(buffer); + if (nRead > 0) { + out.write(buffer, 0, nRead); + result = transport.sendBackupData(nRead); + } + } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK); - // In all cases we need to give the transport its finish callback - int finishResult = transport.finishBackup(); + int finishResult; - if (MORE_DEBUG) { - Slog.i(TAG, "Done trying to send backup data: result=" - + result + " finishResult=" + finishResult); - } + if (!mKeepRunning.get()) { + result = BackupTransport.TRANSPORT_ERROR; + // TODO: tell the transport to abort the backup + Slog.w(TAG, "TODO: tell transport to halt & roll back"); + } - // If we were otherwise in a good state, now interpret the final - // result based on what finishBackup() returned. If we're in a - // failure case already, preserve that result and ignore whatever - // finishBackup() reported. - if (result == BackupTransport.TRANSPORT_OK) { - result = finishResult; - } + // In all cases we need to give the transport its finish callback + finishResult = transport.finishBackup(); - if (result != BackupTransport.TRANSPORT_OK) { - Slog.e(TAG, "Error " + result - + " backing up " + target.packageName); - } + if (MORE_DEBUG) { + Slog.i(TAG, "Done trying to send backup data: result=" + + result + " finishResult=" + finishResult); } - if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { - if (DEBUG) { - Slog.i(TAG, "Transport rejected backup of " + target.packageName - + ", skipping"); - } - // do nothing, clean up, and continue looping - } else if (result != BackupTransport.TRANSPORT_OK) { - if (DEBUG) { - Slog.i(TAG, "Transport failed; aborting backup: " + result); - return; - } + // If we were otherwise in a good state, now interpret the final + // result based on what finishBackup() returned. If we're in a + // failure case already, preserve that result and ignore whatever + // finishBackup() reported. + if (result == BackupTransport.TRANSPORT_OK) { + result = finishResult; + } + + if (result != BackupTransport.TRANSPORT_OK) { + Slog.e(TAG, "Error " + result + + " backing up " + currentPackage.packageName); } - cleanUpPipes(transportPipes); - cleanUpPipes(enginePipes); } - if (DEBUG) { - Slog.i(TAG, "Full backup completed."); + // Roll this package to the end of the backup queue if we're + // in a queue-driven mode (regardless of success/failure) + if (mUpdateSchedule) { + enqueueFullBackup(currentPackage.packageName, + System.currentTimeMillis()); } + + if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { + if (DEBUG) { + Slog.i(TAG, "Transport rejected backup of " + + currentPackage.packageName + + ", skipping"); + } + // do nothing, clean up, and continue looping + } else if (result != BackupTransport.TRANSPORT_OK) { + if (DEBUG) { + Slog.i(TAG, "Transport failed; aborting backup: " + result); + return; + } + } + cleanUpPipes(transportPipes); + cleanUpPipes(enginePipes); + currentPackage = null; + } + + if (DEBUG) { + Slog.i(TAG, "Full backup completed."); } } catch (Exception e) { Slog.w(TAG, "Exception trying full transport backup", e); } finally { cleanUpPipes(transportPipes); cleanUpPipes(enginePipes); + + if (mJob != null) { + mJob.finishBackupPass(); + } + + synchronized (mQueueLock) { + mRunningFullBackupTask = null; + } + synchronized (mLatch) { mLatch.set(true); mLatch.notifyAll(); } + + // Now that we're actually done with schedule-driven work, reschedule + // the next pass based on the new queue state. + if (mUpdateSchedule) { + scheduleNextFullBackupJob(); + } } } @@ -3653,6 +3867,146 @@ public class BackupManagerService extends IBackupManager.Stub { } } + // ----- Full-data backup scheduling ----- + + /** + * Schedule a job to tell us when it's a good time to run a full backup + */ + void scheduleNextFullBackupJob() { + synchronized (mQueueLock) { + if (mFullBackupQueue.size() > 0) { + // schedule the next job at the point in the future when the least-recently + // backed up app comes due for backup again; or immediately if it's already + // due. + long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; + long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; + final long latency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL) + ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0; + Runnable r = new Runnable() { + @Override public void run() { + FullBackupJob.schedule(mContext, latency); + } + }; + mBackupHandler.postDelayed(r, 2500); + } else { + if (DEBUG_SCHEDULING) { + Slog.i(TAG, "Full backup queue empty; not scheduling"); + } + } + } + } + + /** + * Enqueue full backup for the given app, with a note about when it last ran. + */ + void enqueueFullBackup(String packageName, long lastBackedUp) { + FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp); + synchronized (mQueueLock) { + int N = mFullBackupQueue.size(); + // First, sanity check that we aren't adding a duplicate. Slow but + // straightforward; we'll have at most on the order of a few hundred + // items in this list. + for (int i = N-1; i >= 0; i--) { + final FullBackupEntry e = mFullBackupQueue.get(i); + if (packageName.equals(e.packageName)) { + if (DEBUG) { + Slog.w(TAG, "Removing schedule queue dupe of " + packageName); + } + mFullBackupQueue.remove(i); + } + } + + // This is also slow but easy for modest numbers of apps: work backwards + // from the end of the queue until we find an item whose last backup + // time was before this one, then insert this new entry after it. + int which; + for (which = mFullBackupQueue.size() - 1; which >= 0; which--) { + final FullBackupEntry entry = mFullBackupQueue.get(which); + if (entry.lastBackup <= lastBackedUp) { + mFullBackupQueue.add(which + 1, newEntry); + break; + } + } + if (which < 0) { + // this one is earlier than any existing one, so prepend + mFullBackupQueue.add(0, newEntry); + } + } + writeFullBackupScheduleAsync(); + } + + /** + * Conditions are right for a full backup operation, so run one. The model we use is + * to perform one app backup per scheduled job execution, and to reschedule the job + * with zero latency as long as conditions remain right and we still have work to do. + * + * @return Whether ongoing work will continue. The return value here will be passed + * along as the return value to the scheduled job's onStartJob() callback. + */ + boolean beginFullBackup(FullBackupJob scheduledJob) { + long now = System.currentTimeMillis(); + FullBackupEntry entry = null; + + if (DEBUG_SCHEDULING) { + Slog.i(TAG, "Beginning scheduled full backup operation"); + } + + // Great; we're able to run full backup jobs now. See if we have any work to do. + synchronized (mQueueLock) { + if (mRunningFullBackupTask != null) { + Slog.e(TAG, "Backup triggered but one already/still running!"); + return false; + } + + if (mFullBackupQueue.size() == 0) { + // no work to do so just bow out + if (DEBUG) { + Slog.i(TAG, "Backup queue empty; doing nothing"); + } + return false; + } + + entry = mFullBackupQueue.get(0); + long timeSinceRun = now - entry.lastBackup; + if (timeSinceRun < MIN_FULL_BACKUP_INTERVAL) { + // It's too early to back up the next thing in the queue, so bow out + if (MORE_DEBUG) { + Slog.i(TAG, "Device ready but too early to back up next app"); + } + final long latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun; + mBackupHandler.post(new Runnable() { + @Override public void run() { + FullBackupJob.schedule(mContext, latency); + } + }); + return false; + } + + // Okay, the top thing is runnable now. Pop it off and get going. + mFullBackupQueue.remove(0); + AtomicBoolean latch = new AtomicBoolean(false); + String[] pkg = new String[] {entry.packageName}; + mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true, + scheduledJob, latch); + (new Thread(mRunningFullBackupTask)).start(); + } + + return true; + } + + // The job scheduler says our constraints don't hold any more, + // so tear down any ongoing backup task right away. + void endFullBackup() { + synchronized (mQueueLock) { + if (mRunningFullBackupTask != null) { + if (DEBUG_SCHEDULING) { + Slog.i(TAG, "Telling running backup to stop"); + } + mRunningFullBackupTask.setRunning(false); + } + } + } + // ----- Restore infrastructure ----- abstract class RestoreEngine { @@ -6645,8 +6999,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF UnifiedRestoreState nextState = UnifiedRestoreState.FINAL; try { mRestoreDescription = mTransport.nextRestorePackage(); - final int type = mRestoreDescription.getDataType(); - final String pkgName = mRestoreDescription.getPackageName(); + final String pkgName = (mRestoreDescription != null) + ? mRestoreDescription.getPackageName() : null; if (pkgName == null) { Slog.e(TAG, "Failure getting next package name"); EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); @@ -6717,6 +7071,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // Reset per-package preconditions and fire the appropriate next state mWidgetData = null; + final int type = mRestoreDescription.getDataType(); if (type == RestoreDescription.TYPE_KEY_VALUE) { nextState = UnifiedRestoreState.RESTORE_KEYVALUE; } else if (type == RestoreDescription.TYPE_FULL_STREAM) { @@ -7725,7 +8080,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } AtomicBoolean latch = new AtomicBoolean(false); - PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null, pkgNames, latch); + PerformFullTransportBackupTask task = + new PerformFullTransportBackupTask(null, pkgNames, false, null, latch); (new Thread(task, "full-transport-master")).start(); synchronized (latch) { try { @@ -7914,6 +8270,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF if (enable && !wasEnabled && mProvisioned) { // if we've just been enabled, start scheduling backup passes startBackupAlarmsLocked(BACKUP_INTERVAL); + scheduleNextFullBackupJob(); } else if (!enable) { // No longer enabled, so stop running backups if (DEBUG) Slog.i(TAG, "Opting out of backup"); @@ -8470,12 +8827,6 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF throw new SecurityException("No permission to restore other packages"); } - // If the package has no backup agent, we obviously cannot proceed - if (app.applicationInfo.backupAgentName == null) { - Slog.w(TAG, "Asked to restore package " + packageName + " with no agent"); - return -1; - } - // So far so good; we're allowed to try to restore this package. Now // check whether there is data for it in the current dataset, falling back // to the ancestral dataset if not. @@ -8658,10 +9009,16 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF pw.println(" " + pkg); } - pw.println("Pending backup: " + mPendingBackups.size()); + pw.println("Pending key/value backup: " + mPendingBackups.size()); for (BackupRequest req : mPendingBackups.values()) { pw.println(" " + req); } + + pw.println("Full backup queue:" + mFullBackupQueue.size()); + for (FullBackupEntry entry : mFullBackupQueue) { + pw.print(" "); pw.print(entry.lastBackup); + pw.print(" : "); pw.println(entry.packageName); + } } } } diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java new file mode 100644 index 000000000000..deb22934c5ec --- /dev/null +++ b/services/backup/java/com/android/server/backup/FullBackupJob.java @@ -0,0 +1,78 @@ +/* + * 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.backup; + +import android.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.app.job.JobInfo.NetworkType; +import android.content.ComponentName; +import android.content.Context; +import android.util.Slog; + +public class FullBackupJob extends JobService { + private static final String TAG = "FullBackupJob"; + private static final boolean DEBUG = true; + + private static ComponentName sIdleService = + new ComponentName("android", FullBackupJob.class.getName()); + + private static final int JOB_ID = 0x5038; + + JobParameters mParams; + + public static void schedule(Context ctx, long minDelay) { + JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); + JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService) + .setRequiresDeviceIdle(true) + .setRequiredNetworkCapabilities(NetworkType.UNMETERED) + .setRequiresCharging(true); + if (minDelay > 0) { + builder.setMinimumLatency(minDelay); + } + js.schedule(builder.build()); + } + + // callback from the Backup Manager Service: it's finished its work for this pass + public void finishBackupPass() { + if (mParams != null) { + jobFinished(mParams, false); + mParams = null; + } + } + + // ----- scheduled job interface ----- + + @Override + public boolean onStartJob(JobParameters params) { + mParams = params; + BackupManagerService service = BackupManagerService.getInstance(); + return service.beginFullBackup(this); + } + + @Override + public boolean onStopJob(JobParameters params) { + if (mParams != null) { + mParams = null; + BackupManagerService service = BackupManagerService.getInstance(); + service.endFullBackup(); + } + return false; + } + +} diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 5a510a9c9f93..13e1b3761b84 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -96,8 +96,6 @@ public class AppOpsService extends IAppOpsService.Stub { final SparseArray<HashMap<String, Ops>> mUidOps = new SparseArray<HashMap<String, Ops>>(); - private int mDeviceOwnerUid; - private final SparseIntArray mProfileOwnerUids = new SparseIntArray(); private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>(); public final static class Ops extends SparseArray<Op> { @@ -873,15 +871,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - if (userHandle == UserHandle.USER_OWNER) { - if (uid != mDeviceOwnerUid) { - return true; - } - } else { - if (uid != mProfileOwnerUids.get(userHandle, -1)) { - return true; - } - } + return true; } return false; } @@ -1256,35 +1246,6 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public void setDeviceOwner(String packageName) throws RemoteException { - checkSystemUid("setDeviceOwner"); - try { - mDeviceOwnerUid = mContext.getPackageManager().getPackageUid(packageName, - UserHandle.USER_OWNER); - } catch (NameNotFoundException e) { - Log.e(TAG, "Could not find Device Owner UID"); - mDeviceOwnerUid = -1; - throw new IllegalArgumentException("Could not find device owner package " - + packageName); - } - } - - @Override - public void setProfileOwner(String packageName, int userHandle) throws RemoteException { - checkSystemUid("setProfileOwner"); - try { - int uid = mContext.getPackageManager().getPackageUid(packageName, - userHandle); - mProfileOwnerUids.put(userHandle, uid); - } catch (NameNotFoundException e) { - Log.e(TAG, "Could not find Profile Owner UID"); - mProfileOwnerUids.put(userHandle, -1); - throw new IllegalArgumentException("Could not find profile owner package " - + packageName); - } - } - - @Override public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException { checkSystemUid("setUserRestrictions"); boolean[] opRestrictions = mOpRestrictions.get(userHandle); @@ -1306,10 +1267,6 @@ public class AppOpsService extends IAppOpsService.Stub { public void removeUser(int userHandle) throws RemoteException { checkSystemUid("removeUser"); mOpRestrictions.remove(userHandle); - final int index = mProfileOwnerUids.indexOfKey(userHandle); - if (index >= 0) { - mProfileOwnerUids.removeAt(index); - } } private void checkSystemUid(String function) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e44f578e2062..7349ebf08077 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -74,6 +74,7 @@ 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; import android.net.NetworkState; @@ -286,12 +287,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int DISABLED = 0; /** - * used internally as a delayed event to make us switch back to the - * default network - */ - private static final int EVENT_RESTORE_DEFAULT_NETWORK = 1; - - /** * used internally to change our mobile data enabled flag */ private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2; @@ -415,10 +410,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** Handler used for incoming {@link NetworkStateTracker} events. */ final private NetworkStateTrackerHandler mTrackerHandler; - // list of DeathRecipients used to make sure features are turned off when - // a process dies - private List<FeatureUser> mFeatureUsers; - private boolean mSystemReady; private Intent mInitialBroadcast; @@ -764,8 +755,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[i] = new ArrayList<Integer>(); } - mFeatureUsers = new ArrayList<FeatureUser>(); - mTestMode = SystemProperties.get("cm.test.mode").equals("true") && SystemProperties.get("ro.build.type").equals("eng"); @@ -788,7 +777,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper()); + mTethering = new Tethering(mContext, mNetd, statsService, mHandler.getLooper()); //set up the listener for user state for creating user VPNs IntentFilter intentFilter = new IntentFilter(); @@ -816,13 +805,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); - // start network sampling .. - Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null); - mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext, - SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0); - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED); @@ -1321,354 +1304,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; /** - * Used to notice when the calling process dies so we can self-expire - * - * Also used to know if the process has cleaned up after itself when - * our auto-expire timer goes off. The timer has a link to an object. - * - */ - private class FeatureUser implements IBinder.DeathRecipient { - int mNetworkType; - String mFeature; - IBinder mBinder; - int mPid; - int mUid; - long mCreateTime; - - FeatureUser(int type, String feature, IBinder binder) { - super(); - mNetworkType = type; - mFeature = feature; - mBinder = binder; - mPid = getCallingPid(); - mUid = getCallingUid(); - mCreateTime = System.currentTimeMillis(); - - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } - } - - void unlinkDeathRecipient() { - mBinder.unlinkToDeath(this, 0); - } - - public void binderDied() { - log("ConnectivityService FeatureUser binderDied(" + - mNetworkType + ", " + mFeature + ", " + mBinder + "), created " + - (System.currentTimeMillis() - mCreateTime) + " mSec ago"); - stopUsingNetworkFeature(this, false); - } - - public void expire() { - if (VDBG) { - log("ConnectivityService FeatureUser expire(" + - mNetworkType + ", " + mFeature + ", " + mBinder +"), created " + - (System.currentTimeMillis() - mCreateTime) + " mSec ago"); - } - stopUsingNetworkFeature(this, false); - } - - public boolean isSameUser(FeatureUser u) { - if (u == null) return false; - - return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature); - } - - public boolean isSameUser(int pid, int uid, int networkType, String feature) { - if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) && - TextUtils.equals(mFeature, feature)) { - return true; - } - return false; - } - - public String toString() { - return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + - (System.currentTimeMillis() - mCreateTime) + " mSec ago"; - } - } - - // javadoc from interface - public int startUsingNetworkFeature(int networkType, String feature, - IBinder binder) { - long startTime = 0; - if (DBG) { - startTime = SystemClock.elapsedRealtime(); - } - if (VDBG) { - log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid=" - + Binder.getCallingUid()); - } - enforceChangePermission(); - try { - if (!ConnectivityManager.isNetworkTypeValid(networkType) || - mNetConfigs[networkType] == null) { - return PhoneConstants.APN_REQUEST_FAILED; - } - - FeatureUser f = new FeatureUser(networkType, feature, binder); - - // TODO - move this into individual networktrackers - int usedNetworkType = convertFeatureToNetworkType(networkType, feature); - - if (mLockdownEnabled) { - // Since carrier APNs usually aren't available from VPN - // endpoint, mark them as unavailable. - return PhoneConstants.APN_TYPE_NOT_AVAILABLE; - } - - if (mProtectedNetworks.contains(usedNetworkType)) { - enforceConnectivityInternalPermission(); - } - - // if UID is restricted, don't allow them to bring up metered APNs - final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType); - final int uidRules; - synchronized (mRulesLock) { - uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL); - } - if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) { - return PhoneConstants.APN_REQUEST_FAILED; - } - - NetworkStateTracker network = mNetTrackers[usedNetworkType]; - if (network != null) { - Integer currentPid = new Integer(getCallingPid()); - if (usedNetworkType != networkType) { - NetworkInfo ni = network.getNetworkInfo(); - - if (ni.isAvailable() == false) { - if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) { - if (DBG) log("special network not available ni=" + ni.getTypeName()); - return PhoneConstants.APN_TYPE_NOT_AVAILABLE; - } else { - // else make the attempt anyway - probably giving REQUEST_STARTED below - if (DBG) { - log("special network not available, but try anyway ni=" + - ni.getTypeName()); - } - } - } - - int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType); - - synchronized(this) { - boolean addToList = true; - if (restoreTimer < 0) { - // In case there is no timer is specified for the feature, - // make sure we don't add duplicate entry with the same request. - for (FeatureUser u : mFeatureUsers) { - if (u.isSameUser(f)) { - // Duplicate user is found. Do not add. - addToList = false; - break; - } - } - } - - if (addToList) mFeatureUsers.add(f); - if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { - // this gets used for per-pid dns when connected - mNetRequestersPids[usedNetworkType].add(currentPid); - } - } - - if (restoreTimer >= 0) { - mHandler.sendMessageDelayed(mHandler.obtainMessage( - EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer); - } - - if ((ni.isConnectedOrConnecting() == true) && - !network.isTeardownRequested()) { - if (ni.isConnected() == true) { - final long token = Binder.clearCallingIdentity(); - try { - // add the pid-specific dns - handleDnsConfigurationChange(usedNetworkType); - if (VDBG) log("special network already active"); - } finally { - Binder.restoreCallingIdentity(token); - } - return PhoneConstants.APN_ALREADY_ACTIVE; - } - if (VDBG) log("special network already connecting"); - return PhoneConstants.APN_REQUEST_STARTED; - } - - // check if the radio in play can make another contact - // assume if cannot for now - - if (DBG) { - log("startUsingNetworkFeature reconnecting to " + networkType + ": " + - feature); - } - if (network.reconnect()) { - if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED"); - return PhoneConstants.APN_REQUEST_STARTED; - } else { - if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED"); - return PhoneConstants.APN_REQUEST_FAILED; - } - } else { - // need to remember this unsupported request so we respond appropriately on stop - synchronized(this) { - mFeatureUsers.add(f); - if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { - // this gets used for per-pid dns when connected - mNetRequestersPids[usedNetworkType].add(currentPid); - } - } - if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature."); - return -1; - } - } - if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE"); - return PhoneConstants.APN_TYPE_NOT_AVAILABLE; - } finally { - if (DBG) { - final long execTime = SystemClock.elapsedRealtime() - startTime; - if (execTime > 250) { - loge("startUsingNetworkFeature took too long: " + execTime + "ms"); - } else { - if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms"); - } - } - } - } - - // javadoc from interface - public int stopUsingNetworkFeature(int networkType, String feature) { - enforceChangePermission(); - - int pid = getCallingPid(); - int uid = getCallingUid(); - - FeatureUser u = null; - boolean found = false; - - synchronized(this) { - for (FeatureUser x : mFeatureUsers) { - if (x.isSameUser(pid, uid, networkType, feature)) { - u = x; - found = true; - break; - } - } - } - if (found && u != null) { - if (VDBG) log("stopUsingNetworkFeature: X"); - // stop regardless of how many other time this proc had called start - return stopUsingNetworkFeature(u, true); - } else { - // none found! - if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring"); - return 1; - } - } - - private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) { - int networkType = u.mNetworkType; - String feature = u.mFeature; - int pid = u.mPid; - int uid = u.mUid; - - NetworkStateTracker tracker = null; - boolean callTeardown = false; // used to carry our decision outside of sync block - - if (VDBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature); - } - - if (!ConnectivityManager.isNetworkTypeValid(networkType)) { - if (DBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature + - ", net is invalid"); - } - return -1; - } - - // need to link the mFeatureUsers list with the mNetRequestersPids state in this - // sync block - synchronized(this) { - // check if this process still has an outstanding start request - if (!mFeatureUsers.contains(u)) { - if (VDBG) { - log("stopUsingNetworkFeature: this process has no outstanding requests" + - ", ignoring"); - } - return 1; - } - u.unlinkDeathRecipient(); - mFeatureUsers.remove(mFeatureUsers.indexOf(u)); - // If we care about duplicate requests, check for that here. - // - // This is done to support the extension of a request - the app - // can request we start the network feature again and renew the - // auto-shutoff delay. Normal "stop" calls from the app though - // do not pay attention to duplicate requests - in effect the - // API does not refcount and a single stop will counter multiple starts. - if (ignoreDups == false) { - for (FeatureUser x : mFeatureUsers) { - if (x.isSameUser(u)) { - if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring"); - return 1; - } - } - } - - // TODO - move to individual network trackers - int usedNetworkType = convertFeatureToNetworkType(networkType, feature); - - tracker = mNetTrackers[usedNetworkType]; - if (tracker == null) { - if (DBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature + - " no known tracker for used net type " + usedNetworkType); - } - return -1; - } - if (usedNetworkType != networkType) { - Integer currentPid = new Integer(pid); - mNetRequestersPids[usedNetworkType].remove(currentPid); - - final long token = Binder.clearCallingIdentity(); - try { - reassessPidDns(pid, true); - } finally { - Binder.restoreCallingIdentity(token); - } - flushVmDnsCache(); - if (mNetRequestersPids[usedNetworkType].size() != 0) { - if (VDBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature + - " others still using it"); - } - return 1; - } - callTeardown = true; - } else { - if (DBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature + - " not a known feature - dropping"); - } - } - } - - if (callTeardown) { - if (DBG) { - log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature); - } - tracker.teardown(); - return 1; - } else { - return -1; - } - } - - /** * Ensure that a network route exists to deliver traffic to the specified * host via the specified network interface. * @param networkType the type of the network over which traffic to the @@ -2144,6 +1779,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void systemReady() { + // start network sampling .. + Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED); + intent.setPackage(mContext.getPackageName()); + + mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext, + SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0); + setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent); + if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) { mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); } @@ -2937,7 +2580,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } try { mNetd.addVpnUidRanges(nai.network.netId, (UidRange[])msg.obj); - } catch (RemoteException e) { + } catch (Exception e) { + // Never crash! + loge("Exception in addVpnUidRanges: " + e); } break; } @@ -2949,7 +2594,39 @@ public class ConnectivityService extends IConnectivityManager.Stub { } try { mNetd.removeVpnUidRanges(nai.network.netId, (UidRange[])msg.obj); - } catch (RemoteException e) { + } catch (Exception e) { + // Never crash! + loge("Exception in removeVpnUidRanges: " + e); + } + break; + } + case NetworkAgent.EVENT_BLOCK_ADDRESS_FAMILY: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("EVENT_BLOCK_ADDRESS_FAMILY from unknown NetworkAgent"); + break; + } + try { + mNetd.blockAddressFamily((Integer) msg.obj, nai.network.netId, + nai.linkProperties.getInterfaceName()); + } catch (Exception e) { + // Never crash! + loge("Exception in blockAddressFamily: " + e); + } + break; + } + case NetworkAgent.EVENT_UNBLOCK_ADDRESS_FAMILY: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("EVENT_UNBLOCK_ADDRESS_FAMILY from unknown NetworkAgent"); + break; + } + try { + mNetd.unblockAddressFamily((Integer) msg.obj, nai.network.netId, + nai.linkProperties.getInterfaceName()); + } catch (Exception e) { + // Never crash! + loge("Exception in blockAddressFamily: " + e); } break; } @@ -3221,6 +2898,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } if (DBG) log("releasing NetworkRequest " + request); + nri.unlinkDeathRecipient(); mNetworkRequests.remove(request); // tell the network currently servicing this that it's no longer interested NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId); @@ -3289,11 +2967,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } break; } - case EVENT_RESTORE_DEFAULT_NETWORK: { - FeatureUser u = (FeatureUser)msg.obj; - u.expire(); - break; - } case EVENT_INET_CONDITION_CHANGE: { int netType = msg.arg1; int condition = msg.arg2; @@ -4355,6 +4028,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // First wait until we can start using hipri Binder binder = new Binder(); +/* while(SystemClock.elapsedRealtime() < endTime) { int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_HIPRI, binder); @@ -4367,7 +4041,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { result = CMP_RESULT_CODE_NO_CONNECTION; sleep(POLLING_SLEEP_SEC); } - +*/ // Continue trying to connect until time has run out while(SystemClock.elapsedRealtime() < endTime) { try { @@ -4550,8 +4224,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } finally { log("isMobileOk: F stop hipri"); mCs.setEnableFailFastMobileData(DctConstants.DISABLED); - mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - Phone.FEATURE_ENABLE_HIPRI); +// mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, +// Phone.FEATURE_ENABLE_HIPRI); // Wait for hipri to disconnect. long endTime = SystemClock.elapsedRealtime() + 5000; @@ -5107,6 +4781,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * Tracks info about the requester. + * Also used to notice when the calling process dies so we can self-expire + */ private class NetworkRequestInfo implements IBinder.DeathRecipient { static final boolean REQUEST = true; static final boolean LISTEN = false; @@ -5160,11 +4838,27 @@ public class ConnectivityService extends IConnectivityManager.Stub { enforceChangePermission(); } + networkCapabilities = new NetworkCapabilities(networkCapabilities); + + // if UID is restricted, don't allow them to bring up metered APNs + if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + == false) { + final int uidRules; + synchronized(mRulesLock) { + uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL); + } + if ((uidRules & RULE_REJECT_METERED) != 0) { + // we could silently fail or we can filter the available nets to only give + // them those they have access to. Chose the more useful + networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } + } + if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) { throw new IllegalArgumentException("Bad timeout specified"); } - NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities), legacyType, nextNetworkRequestId()); + NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, + nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); @@ -5259,12 +4953,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, - int currentScore) { + int currentScore, NetworkMisc networkMisc) { enforceConnectivityInternalPermission(); NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(), new NetworkInfo(networkInfo), new LinkProperties(linkProperties), - new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler); + new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler, + networkMisc); if (VDBG) log("registerNetworkAgent " + nai); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai)); } @@ -5665,7 +5360,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { // to tell us whether we've already created this network or not. if (networkAgent.isVPN()) { mNetd.createVirtualNetwork(networkAgent.network.netId, - !networkAgent.linkProperties.getDnsServers().isEmpty()); + !networkAgent.linkProperties.getDnsServers().isEmpty(), + (networkAgent.networkMisc == null || + !networkAgent.networkMisc.allowBypass)); } else { mNetd.createPhysicalNetwork(networkAgent.network.netId); } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 6c3a4b4bdb11..50f2ae9ce266 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -775,7 +775,7 @@ class MountService extends IMountService.Stub */ try { final String[] vols = NativeDaemonEvent.filterMessageList( - mConnector.executeForList("volume", "list"), + mConnector.executeForList("volume", "list", "broadcast"), VoldResponseCode.VolumeListResult); for (String volstr : vols) { String[] tok = volstr.split(" "); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index db423b02b702..362a74502aaf 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -25,6 +25,8 @@ import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_TETHERING; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult; import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult; import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult; @@ -85,6 +87,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; @@ -1947,11 +1950,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override - public void createVirtualNetwork(int netId, boolean hasDNS) { + public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { - mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0"); + mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0", + secure ? "1" : "0"); } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); } @@ -2101,4 +2105,36 @@ public class NetworkManagementService extends INetworkManagementService.Stub public void removeInterfaceFromLocalNetwork(String iface) { modifyInterfaceInNetwork("remove", "local", iface); } + + @Override + public void blockAddressFamily(int family, int netId, String iface) { + modifyAddressFamily("add", family, netId, iface); + } + + @Override + public void unblockAddressFamily(int family, int netId, String iface) { + modifyAddressFamily("remove", family, netId, iface); + } + + private void modifyAddressFamily(String action, int family, int netId, String iface) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + + final Command cmd = new Command("network", "route", action, netId, iface); + + if (family == AF_INET) { + cmd.appendArg(Inet4Address.ANY.getHostAddress() + "/0"); + } else if (family == AF_INET6) { + cmd.appendArg(Inet6Address.ANY.getHostAddress() + "/0"); + } else { + throw new IllegalStateException(family + " is neither " + AF_INET + " nor " + AF_INET6); + } + + cmd.appendArg("unreachable"); + + try { + mConnector.execute(cmd); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 87084d5cc2c1..cb410efebff3 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -67,12 +67,22 @@ import com.android.server.am.BatteryStatsService; /** * Since phone process can be restarted, this class provides a centralized place * that applications can register and be called back from. + * + * Change-Id: I450c968bda93767554b5188ee63e10c9f43c5aa4 fixes bugs 16148026 + * and 15973975 by saving the phoneId of the registrant and then using the + * phoneId when deciding to to make a callback. This is necessary because + * a subId changes from to a dummy value when a SIM is removed and thus won't + * compare properly. Because SubscriptionManager.getPhoneId(long subId) handles + * the dummy value conversion we properly do the callbacks. + * + * Eventually we may want to remove the notion of dummy value but for now this + * looks like the best approach. */ class TelephonyRegistry extends ITelephonyRegistry.Stub { private static final String TAG = "TelephonyRegistry"; - private static final boolean DBG = false; // STOPSHIP if true + private static final boolean DBG = true; // STOPSHIP if true private static final boolean DBG_LOC = false; // STOPSHIP if true - private static final boolean VDBG = false; // STOPSHIP if true + private static final boolean VDBG = true; // STOPSHIP if true private static class Record { String pkgForDebug; @@ -87,12 +97,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { long subId; + int phoneId; + boolean isLegacyApp; @Override public String toString() { return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid + " subId=" + subId + - " events=" + Integer.toHexString(events) + "}"; + " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}"; } } @@ -146,6 +158,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private long mDefaultSubId; + private int mDefaultPhoneIdForDefaultSubId; + private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo(); private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE; @@ -179,15 +193,19 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void handleMessage(Message msg) { switch (msg.what) { case MSG_USER_SWITCHED: { - log("MSG_USER_SWITCHED userId=" + msg.arg1); + if (VDBG) log("MSG_USER_SWITCHED userId=" + msg.arg1); int numPhones = TelephonyManager.getDefault().getPhoneCount(); for (int sub = 0; sub < numPhones; sub++) { - TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]); + TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, + mCellLocation[sub]); } break; } case MSG_UPDATE_DEFAULT_SUB: { - log("MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId); + if (VDBG) { + log("MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId + + " phoneId=" + mDefaultPhoneIdForDefaultSubId); + } // Default subscription id changed, update the changed default subscription // id in all the legacy application listener records. synchronized (mRecords) { @@ -195,6 +213,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { // FIXME: Be sure we're using isLegacyApp correctly! if (r.isLegacyApp == true) { r.subId = mDefaultSubId; + r.phoneId = mDefaultPhoneIdForDefaultSubId; } } } @@ -208,7 +227,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - log("mBroadcastReceiver: action=" + action); + if (VDBG) log("mBroadcastReceiver: action=" + action); if (Intent.ACTION_USER_SWITCHED.equals(action)) { int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); if (DBG) log("onReceive: userHandle=" + userHandle); @@ -216,7 +235,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) { mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY, SubscriptionManager.getDefaultSubId()); - if (DBG) log("onReceive: mDefaultSubId=" + mDefaultSubId); + mDefaultPhoneIdForDefaultSubId = intent.getIntExtra(PhoneConstants.SLOT_KEY, + SubscriptionManager.getPhoneId(mDefaultSubId)); + if (DBG) { + log("onReceive: mDefaultSubId=" + mDefaultSubId + + " mDefaultPhoneIdForDefaultSubId=" + mDefaultPhoneIdForDefaultSubId); + } mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0)); } } @@ -236,8 +260,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mBatteryStats = BatteryStatsService.getService(); mConnectedApns = new ArrayList<String>(); - // Initialize default subscription to be used for single standby. + // Initialize default subId and its phoneId. mDefaultSubId = SubscriptionManager.getDefaultSubId(); + mDefaultPhoneIdForDefaultSubId = SubscriptionManager.getPhoneId(mDefaultSubId); int numPhones = TelephonyManager.getDefault().getPhoneCount(); if (DBG) log("TelephonyRegistor: ctor numPhones=" + numPhones); @@ -310,9 +335,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { boolean notifyNow, long subId, boolean isLegacyApp) { int callerUid = UserHandle.getCallingUserId(); int myUid = UserHandle.myUserId(); - if (true /*VDBG*/) { + int phoneId = SubscriptionManager.getPhoneId(subId); + if (VDBG) { log("listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events) - + " notifyNow=" + notifyNow + " subId=" + subId + + " notifyNow=" + notifyNow + " subId=" + subId + " phoneId=" + phoneId + " isLegacyApp=" + isLegacyApp + " myUid=" + myUid + " callerUid=" + callerUid); @@ -339,29 +365,33 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { r.pkgForDebug = pkgForDebug; r.callerUid = callerUid; r.subId = subId; + r.phoneId = phoneId; r.isLegacyApp = isLegacyApp; // Legacy applications pass invalid subId(-1), based on // the received subId value update the isLegacyApp field if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) { r.subId = mDefaultSubId; - r.isLegacyApp = true; // r.subId is to be update when default changes. + r.phoneId = mDefaultPhoneIdForDefaultSubId; + r.isLegacyApp = true; // subId & phoneId are updated when default changes. } if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) { r.subId = mDefaultSubId; - r.isLegacyApp = true; // r.subId is to be update when default changes. - if (true/*DBG*/) log("listen: DEFAULT_SUB_ID"); + r.phoneId = mDefaultPhoneIdForDefaultSubId; + r.isLegacyApp = true; // subId & phoneId are updated when default changes. + if (DBG) log("listen: DEFAULT_SUB_ID"); } mRecords.add(r); - if (true/*DBG*/) log("listen: add new record"); + if (DBG) log("listen: add new record"); } - int phoneId = SubscriptionManager.getPhoneId(subId); r.events = events; - if (true/*DBG*/) log("listen: set events record=" + r + " subId=" + subId + " phoneId=" + phoneId); - toStringLogSSC("listen"); + if (DBG) { + log("listen: r=" + r + " subId=" + subId + " phoneId=" + phoneId); + } + if (VDBG) toStringLogSSC("listen"); if (notifyNow && validatePhoneId(phoneId)) { if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { try { - log("listen: call onSSC state=" + mServiceState[phoneId]); + if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]); r.callback.onServiceStateChanged( new ServiceState(mServiceState[phoneId])); } catch (RemoteException ex) { @@ -516,7 +546,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifyCallState()")) { return; } - if (true /*VDBG*/) { + if (VDBG) { log("notifyCallStateUsingSubId: subId=" + subId + " state=" + state + " incomingNumber=" + incomingNumber); } @@ -527,8 +557,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallIncomingNumber[phoneId] = incomingNumber; for (Record r : mRecords) { if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) && - (r.subId == subId) && (r.isLegacyApp == false)) { - // FIXME: why isLegacyApp false? + (r.phoneId == phoneId) && + (r.isLegacyApp == false)) { // FIXME: why isLegacyApp false? try { r.callback.onCallStateChanged(state, incomingNumber); } catch (RemoteException ex) { @@ -552,27 +582,32 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (subId == SubscriptionManager.DEFAULT_SUB_ID) { subId = mDefaultSubId; - log("notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId); + if (VDBG) log("notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId); } synchronized (mRecords) { int phoneId = SubscriptionManager.getPhoneId(subId); - if (true/*VDBG*/) { + if (VDBG) { log("notifyServiceStateUsingSubId: subId=" + subId + " phoneId=" + phoneId + " state=" + state); } if (validatePhoneId(phoneId)) { mServiceState[phoneId] = state; logServiceStateChanged("notifyServiceStateUsingSubId", subId, phoneId, state); - toStringLogSSC("notifyServiceStateUsingSubId"); + if (VDBG) toStringLogSSC("notifyServiceStateUsingSubId"); for (Record r : mRecords) { - log("notifyServiceStateUsingSubId: r.events=0x" + Integer.toHexString(r.events) + " r.subId=" + r.subId + " subId=" + subId + " state=" + state); - // FIXME: use DEFAULT_SUB_ID instead?? + if (VDBG) { + log("notifyServiceStateUsingSubId: r=" + r + " subId=" + subId + + " phoneId=" + phoneId + " state=" + state); + } if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) && - (r.subId == subId)) { + (r.phoneId == phoneId)) { try { - log("notifyServiceStateUsingSubId: call onSSC subId=" + subId - + " state=" + state); + if (DBG) { + log("notifyServiceStateUsingSubId: callback.onSSC r=" + r + + " subId=" + subId + " phoneId=" + phoneId + + " state=" + state); + } r.callback.onServiceStateChanged(new ServiceState(state)); } catch (RemoteException ex) { mRemoveList.add(r.binder); @@ -595,7 +630,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifySignalStrength()")) { return; } - if (true/*VDBG*/) { + if (VDBG) { log("notifySignalStrengthUsingSubId: subId=" + subId + " signalStrength=" + signalStrength); toStringLogSSC("notifySignalStrengthUsingSubId"); @@ -603,25 +638,36 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { int phoneId = SubscriptionManager.getPhoneId(subId); if (validatePhoneId(phoneId)) { - log("notifySignalStrengthUsingSubId: valid phoneId=" + phoneId); + if (VDBG) log("notifySignalStrengthUsingSubId: valid phoneId=" + phoneId); mSignalStrength[phoneId] = signalStrength; for (Record r : mRecords) { - log("notifySignalStrengthUsingSubId: r.events=0x" + Integer.toHexString(r.events) + " r.subId=" + r.subId + " subId=" + subId); + if (VDBG) { + log("notifySignalStrengthUsingSubId: r=" + r + " subId=" + subId + + " phoneId=" + phoneId + " ss=" + signalStrength); + } if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) && - (r.subId == subId)){ + (r.phoneId == phoneId)) { try { - log("notifySignalStrengthUsingSubId: callback.onSsS ss=" + signalStrength); + if (DBG) { + log("notifySignalStrengthUsingSubId: callback.onSsS r=" + r + + " subId=" + subId + " phoneId=" + phoneId + + " ss=" + signalStrength); + } r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } } if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) && - (r.subId == subId)) { + (r.phoneId == phoneId)) { try { int gsmSignalStrength = signalStrength.getGsmSignalStrength(); int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); - log("notifySignalStrengthUsingSubId: callback.onSS gsmSS=" + gsmSignalStrength + " ss=" + ss); + if (DBG) { + log("notifySignalStrengthUsingSubId: callback.onSS r=" + r + + " subId=" + subId + " phoneId=" + phoneId + + " gsmSS=" + gsmSignalStrength + " ss=" + ss); + } r.callback.onSignalStrengthChanged(ss); } catch (RemoteException ex) { mRemoveList.add(r.binder); @@ -714,7 +760,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mMessageWaiting[phoneId] = mwi; for (Record r : mRecords) { if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) && - (r.subId == subId)) { + (r.phoneId == phoneId)) { try { r.callback.onMessageWaitingIndicatorChanged(mwi); } catch (RemoteException ex) { @@ -745,7 +791,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallForwarding[phoneId] = cfi; for (Record r : mRecords) { if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) && - (r.subId == subId)) { + (r.phoneId == phoneId)) { try { r.callback.onCallForwardingIndicatorChanged(cfi); } catch (RemoteException ex) { @@ -842,7 +888,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } for (Record r : mRecords) { if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) && - (r.subId == subId)) { + (r.phoneId == phoneId)) { try { log("Notify data connection state changed on sub: " + subId); @@ -1092,8 +1138,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println(" mDcRtInfo=" + mDcRtInfo); pw.println("registrations: count=" + recordCount); for (Record r : mRecords) { - pw.println(" " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events)); - pw.println("is Legacy = " + r.isLegacyApp + " subId = " + r.subId); + pw.println(" " + r); } } } @@ -1360,6 +1405,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { i = 0; } } while (i != next); + log(prompt + ": ----------------"); } } } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 248a3037dc1f..20f6f1ccffec 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -55,6 +55,7 @@ import java.util.ListIterator; public class VibratorService extends IVibratorService.Stub implements InputManager.InputDeviceListener { private static final String TAG = "VibratorService"; + private static final boolean DEBUG = false; private final LinkedList<Vibration> mVibrations; private Vibration mCurrentVibration; @@ -205,6 +206,7 @@ public class VibratorService extends IVibratorService.Stub } } + @Override // Binder call public boolean hasVibrator() { return doVibratorExists(); } @@ -220,6 +222,7 @@ public class VibratorService extends IVibratorService.Stub Binder.getCallingPid(), Binder.getCallingUid(), null); } + @Override // Binder call public void vibrate(int uid, String opPkg, long milliseconds, int usageHint, IBinder token) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) @@ -237,6 +240,10 @@ public class VibratorService extends IVibratorService.Stub return; } + if (DEBUG) { + Slog.d(TAG, "Vibrating for " + milliseconds + " ms."); + } + Vibration vib = new Vibration(token, milliseconds, usageHint, uid, opPkg); final long ident = Binder.clearCallingIdentity(); @@ -262,6 +269,7 @@ public class VibratorService extends IVibratorService.Stub return true; } + @Override // Binder call public void vibratePattern(int uid, String packageName, long[] pattern, int repeat, int usageHint, IBinder token) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) @@ -272,13 +280,13 @@ public class VibratorService extends IVibratorService.Stub // so wakelock calls will succeed long identity = Binder.clearCallingIdentity(); try { - if (false) { + if (DEBUG) { String s = ""; int N = pattern.length; for (int i=0; i<N; i++) { s += " " + pattern[i]; } - Slog.i(TAG, "vibrating with pattern: " + s); + Slog.d(TAG, "Vibrating with pattern:" + s); } // we're running in the server so we can't fail @@ -314,6 +322,7 @@ public class VibratorService extends IVibratorService.Stub } } + @Override // Binder call public void cancelVibrate(IBinder token) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.VIBRATE, @@ -325,6 +334,9 @@ public class VibratorService extends IVibratorService.Stub synchronized (mVibrations) { final Vibration vib = removeVibrationLocked(token); if (vib == mCurrentVibration) { + if (DEBUG) { + Slog.d(TAG, "Canceling vibration."); + } doCancelVibrateLocked(); startNextVibrationLocked(); } @@ -336,6 +348,7 @@ public class VibratorService extends IVibratorService.Stub } private final Runnable mVibrationRunnable = new Runnable() { + @Override public void run() { synchronized (mVibrations) { doCancelVibrateLocked(); @@ -516,6 +529,9 @@ public class VibratorService extends IVibratorService.Stub private void doVibratorOn(long millis, int uid, int usageHint) { synchronized (mInputDeviceVibrators) { + if (DEBUG) { + Slog.d(TAG, "Turning vibrator on for " + millis + " ms."); + } try { mBatteryStatsService.noteVibratorOn(uid, millis); mCurVibUid = uid; @@ -536,6 +552,9 @@ public class VibratorService extends IVibratorService.Stub private void doVibratorOff() { synchronized (mInputDeviceVibrators) { + if (DEBUG) { + Slog.d(TAG, "Turning vibrator off."); + } if (mCurVibUid >= 0) { try { mBatteryStatsService.noteVibratorOff(mCurVibUid); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c0ac0238dbf0..d7b2a98c9153 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -46,8 +46,8 @@ import android.os.PersistableBundle; import android.service.voice.IVoiceInteractionSession; import android.util.ArrayMap; import android.util.ArraySet; - import android.util.SparseIntArray; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; @@ -222,7 +222,11 @@ import java.util.concurrent.atomic.AtomicLong; public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { + private static final String USER_DATA_DIR = "/data/user/"; + // File that stores last updated system version and called preboot receivers + static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat"; + static final String TAG = "ActivityManager"; static final String TAG_MU = "ActivityManagerServiceMU"; static final boolean DEBUG = false; @@ -354,6 +358,8 @@ public final class ActivityManagerService extends ActivityManagerNative static final int ALLOW_NON_FULL_IN_PROFILE = 1; static final int ALLOW_FULL_ONLY = 2; + static final int LAST_PREBOOT_DELIVERED_FILE_VERSION = 10000; + /** All system services */ SystemServiceManager mSystemServiceManager; @@ -1152,6 +1158,8 @@ public final class ActivityManagerService extends ActivityManagerNative static final int UPDATE_TIME = 41; static final int SYSTEM_USER_START_MSG = 42; static final int SYSTEM_USER_CURRENT_MSG = 43; + static final int ENTER_ANIMATION_COMPLETE_MSG = 44; + static final int ENABLE_SCREEN_AFTER_BOOT_MSG = 45; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1807,6 +1815,22 @@ public final class ActivityManagerService extends ActivityManagerNative mSystemServiceManager.switchUser(msg.arg1); break; } + case ENTER_ANIMATION_COMPLETE_MSG: { + synchronized (ActivityManagerService.this) { + ActivityRecord r = ActivityRecord.forToken((IBinder) msg.obj); + if (r != null && r.app != null && r.app.thread != null) { + try { + r.app.thread.scheduleEnterAnimationComplete(r.appToken); + } catch (RemoteException e) { + } + } + } + break; + } + case ENABLE_SCREEN_AFTER_BOOT_MSG: { + enableScreenAfterBoot(); + break; + } } } }; @@ -3079,7 +3103,8 @@ public final class ActivityManagerService extends ActivityManagerNative final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); if (resumed) { if (mUsageStatsService != null) { - mUsageStatsService.reportEvent(component.realActivity, System.currentTimeMillis(), + mUsageStatsService.reportEvent(component.realActivity, component.userId, + System.currentTimeMillis(), UsageStats.Event.MOVE_TO_FOREGROUND); } synchronized (stats) { @@ -3087,7 +3112,8 @@ public final class ActivityManagerService extends ActivityManagerNative } } else { if (mUsageStatsService != null) { - mUsageStatsService.reportEvent(component.realActivity, System.currentTimeMillis(), + mUsageStatsService.reportEvent(component.realActivity, component.userId, + System.currentTimeMillis(), UsageStats.Event.MOVE_TO_BACKGROUND); } synchronized (stats) { @@ -5504,6 +5530,10 @@ public final class ActivityManagerService extends ActivityManagerNative Binder.restoreCallingIdentity(origId); } + void postEnableScreenAfterBootLocked() { + mHandler.sendEmptyMessage(ENABLE_SCREEN_AFTER_BOOT_MSG); + } + void enableScreenAfterBoot() { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN, SystemClock.uptimeMillis()); @@ -5693,6 +5723,11 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override + public final void notifyEnterAnimationComplete(IBinder token) { + mHandler.sendMessage(mHandler.obtainMessage(ENTER_ANIMATION_COMPLETE_MSG, token)); + } + + @Override public String getCallingPackage(IBinder token) { synchronized (this) { ActivityRecord r = getCallingRecordLocked(token); @@ -6620,6 +6655,11 @@ public final class ActivityManagerService extends ActivityManagerNative if (data == null && clip == null) { return null; } + // Default userId for uris in the intent (if they don't specify it themselves) + int contentUserHint = intent.getContentUserHint(); + if (contentUserHint == UserHandle.USER_CURRENT) { + contentUserHint = UserHandle.getUserId(callingUid); + } final IPackageManager pm = AppGlobals.getPackageManager(); int targetUid; if (needed != null) { @@ -6639,7 +6679,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } if (data != null) { - GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), data); + GrantUri grantUri = GrantUri.resolve(contentUserHint, data); targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode, targetUid); if (targetUid > 0) { @@ -6653,7 +6693,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<clip.getItemCount(); i++) { Uri uri = clip.getItemAt(i).getUri(); if (uri != null) { - GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), uri); + GrantUri grantUri = GrantUri.resolve(contentUserHint, uri); targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode, targetUid); if (targetUid > 0) { @@ -9519,13 +9559,17 @@ public final class ActivityManagerService extends ActivityManagerNative if (r == null) { return false; } + int index = r.task.mActivities.lastIndexOf(r); + if (index > 0) { + ActivityRecord under = r.task.mActivities.get(index - 1); + under.returningOptions = options; + } if (r.changeWindowTranslucency(false)) { - r.task.stack.convertToTranslucent(r, options); + r.task.stack.convertToTranslucent(r); mWindowManager.setAppFullscreen(token, false); mStackSupervisor.ensureActivitiesVisibleLocked(null, 0); return true; } else { - r.task.stack.mReturningActivityOptions = options; mStackSupervisor.ensureActivitiesVisibleLocked(null, 0); return false; } @@ -9947,12 +9991,10 @@ public final class ActivityManagerService extends ActivityManagerNative private static File getCalledPreBootReceiversFile() { File dataDir = Environment.getDataDirectory(); File systemDir = new File(dataDir, "system"); - File fname = new File(systemDir, "called_pre_boots.dat"); + File fname = new File(systemDir, CALLED_PRE_BOOTS_FILENAME); return fname; } - static final int LAST_DONE_VERSION = 10000; - private static ArrayList<ComponentName> readLastDonePreBootReceivers() { ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>(); File file = getCalledPreBootReceiversFile(); @@ -9961,7 +10003,7 @@ public final class ActivityManagerService extends ActivityManagerNative fis = new FileInputStream(file); DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048)); int fvers = dis.readInt(); - if (fvers == LAST_DONE_VERSION) { + if (fvers == LAST_PREBOOT_DELIVERED_FILE_VERSION) { String vers = dis.readUTF(); String codename = dis.readUTF(); String build = dis.readUTF(); @@ -9990,16 +10032,15 @@ public final class ActivityManagerService extends ActivityManagerNative } return lastDoneReceivers; } - + private static void writeLastDonePreBootReceivers(ArrayList<ComponentName> list) { File file = getCalledPreBootReceiversFile(); FileOutputStream fos = null; DataOutputStream dos = null; try { - Slog.i(TAG, "Writing new set of last done pre-boot receivers..."); fos = new FileOutputStream(file); dos = new DataOutputStream(new BufferedOutputStream(fos, 2048)); - dos.writeInt(LAST_DONE_VERSION); + dos.writeInt(LAST_PREBOOT_DELIVERED_FILE_VERSION); dos.writeUTF(android.os.Build.VERSION.RELEASE); dos.writeUTF(android.os.Build.VERSION.CODENAME); dos.writeUTF(android.os.Build.VERSION.INCREMENTAL); @@ -10023,11 +10064,92 @@ public final class ActivityManagerService extends ActivityManagerNative } } } - + + private boolean deliverPreBootCompleted(final Runnable onFinishCallback, + ArrayList<ComponentName> doneReceivers, int userId) { + boolean waitingUpdate = false; + Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); + List<ResolveInfo> ris = null; + try { + ris = AppGlobals.getPackageManager().queryIntentReceivers( + intent, null, 0, userId); + } catch (RemoteException e) { + } + if (ris != null) { + for (int i=ris.size()-1; i>=0; i--) { + if ((ris.get(i).activityInfo.applicationInfo.flags + &ApplicationInfo.FLAG_SYSTEM) == 0) { + ris.remove(i); + } + } + intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE); + + // For User 0, load the version number. When delivering to a new user, deliver + // to all receivers. + if (userId == UserHandle.USER_OWNER) { + ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers(); + for (int i=0; i<ris.size(); i++) { + ActivityInfo ai = ris.get(i).activityInfo; + ComponentName comp = new ComponentName(ai.packageName, ai.name); + if (lastDoneReceivers.contains(comp)) { + // We already did the pre boot receiver for this app with the current + // platform version, so don't do it again... + ris.remove(i); + i--; + // ...however, do keep it as one that has been done, so we don't + // forget about it when rewriting the file of last done receivers. + doneReceivers.add(comp); + } + } + } + + // If primary user, send broadcast to all available users, else just to userId + final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked() + : new int[] { userId }; + for (int i = 0; i < ris.size(); i++) { + ActivityInfo ai = ris.get(i).activityInfo; + ComponentName comp = new ComponentName(ai.packageName, ai.name); + doneReceivers.add(comp); + intent.setComponent(comp); + for (int j=0; j<users.length; j++) { + IIntentReceiver finisher = null; + // On last receiver and user, set up a completion callback + if (i == ris.size() - 1 && j == users.length - 1 && onFinishCallback != null) { + finisher = new IIntentReceiver.Stub() { + public void performReceive(Intent intent, int resultCode, + String data, Bundle extras, boolean ordered, + boolean sticky, int sendingUser) { + // The raw IIntentReceiver interface is called + // with the AM lock held, so redispatch to + // execute our code without the lock. + mHandler.post(onFinishCallback); + } + }; + } + Slog.i(TAG, "Sending system update to " + intent.getComponent() + + " for user " + users[j]); + broadcastIntentLocked(null, null, intent, null, finisher, + 0, null, null, null, AppOpsManager.OP_NONE, + true, false, MY_PID, Process.SYSTEM_UID, + users[j]); + if (finisher != null) { + waitingUpdate = true; + } + } + } + } + + return waitingUpdate; + } + public void systemReady(final Runnable goingCallback) { synchronized(this) { if (mSystemReady) { - if (goingCallback != null) goingCallback.run(); + // If we're done calling all the receivers, run the next "boot phase" passed in + // by the SystemServer + if (goingCallback != null) { + goingCallback.run(); + } return; } @@ -10048,82 +10170,20 @@ public final class ActivityManagerService extends ActivityManagerNative if (mWaitingUpdate) { return; } - Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); - List<ResolveInfo> ris = null; - try { - ris = AppGlobals.getPackageManager().queryIntentReceivers( - intent, null, 0, 0); - } catch (RemoteException e) { - } - if (ris != null) { - for (int i=ris.size()-1; i>=0; i--) { - if ((ris.get(i).activityInfo.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) == 0) { - ris.remove(i); - } - } - intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE); - - ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers(); - - final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>(); - for (int i=0; i<ris.size(); i++) { - ActivityInfo ai = ris.get(i).activityInfo; - ComponentName comp = new ComponentName(ai.packageName, ai.name); - if (lastDoneReceivers.contains(comp)) { - // We already did the pre boot receiver for this app with the current - // platform version, so don't do it again... - ris.remove(i); - i--; - // ...however, do keep it as one that has been done, so we don't - // forget about it when rewriting the file of last done receivers. - doneReceivers.add(comp); + final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>(); + mWaitingUpdate = deliverPreBootCompleted(new Runnable() { + public void run() { + synchronized (ActivityManagerService.this) { + mDidUpdate = true; } + writeLastDonePreBootReceivers(doneReceivers); + showBootMessage(mContext.getText( + R.string.android_upgrading_complete), + false); + systemReady(goingCallback); } + }, doneReceivers, UserHandle.USER_OWNER); - final int[] users = getUsersLocked(); - for (int i=0; i<ris.size(); i++) { - ActivityInfo ai = ris.get(i).activityInfo; - ComponentName comp = new ComponentName(ai.packageName, ai.name); - doneReceivers.add(comp); - intent.setComponent(comp); - for (int j=0; j<users.length; j++) { - IIntentReceiver finisher = null; - if (i == ris.size()-1 && j == users.length-1) { - finisher = new IIntentReceiver.Stub() { - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean ordered, - boolean sticky, int sendingUser) { - // The raw IIntentReceiver interface is called - // with the AM lock held, so redispatch to - // execute our code without the lock. - mHandler.post(new Runnable() { - public void run() { - synchronized (ActivityManagerService.this) { - mDidUpdate = true; - } - writeLastDonePreBootReceivers(doneReceivers); - showBootMessage(mContext.getText( - R.string.android_upgrading_complete), - false); - systemReady(goingCallback); - } - }); - } - }; - } - Slog.i(TAG, "Sending system update to " + intent.getComponent() - + " for user " + users[j]); - broadcastIntentLocked(null, null, intent, null, finisher, - 0, null, null, null, AppOpsManager.OP_NONE, - true, false, MY_PID, Process.SYSTEM_UID, - users[j]); - if (finisher != null) { - mWaitingUpdate = true; - } - } - } - } if (mWaitingUpdate) { return; } @@ -17156,6 +17216,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (needStart) { + // Send USER_STARTED broadcast Intent intent = new Intent(Intent.ACTION_USER_STARTED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); @@ -17167,6 +17228,11 @@ public final class ActivityManagerService extends ActivityManagerNative if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) { if (userId != UserHandle.USER_OWNER) { + // Send PRE_BOOT_COMPLETED broadcasts for this new user + final ArrayList<ComponentName> doneReceivers + = new ArrayList<ComponentName>(); + deliverPreBootCompleted(null, doneReceivers, userId); + Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); broadcastIntentLocked(null, null, intent, null, diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 85f49ed43ae4..e528d57636c5 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -130,6 +130,7 @@ final class ActivityRecord { HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act ArrayList<Intent> newIntents; // any pending new intents for single-top mode ActivityOptions pendingOptions; // most recently given options + ActivityOptions returningOptions; // options that are coming back via convertToTranslucent HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold UriPermissionOwner uriPermissions; // current special URI access perms. ProcessRecord app; // if non-null, hosting application diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 91bc7e3b0afa..4766742a5639 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -211,9 +211,6 @@ final class ActivityStack { ActivityRecord mTranslucentActivityWaiting = null; private ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<ActivityRecord>(); - // Options passed from the caller of the convertToTranslucent to the activity that will - // appear below it. - ActivityOptions mReturningActivityOptions = null; /** * Set when we know we are going to be calling updateConfiguration() @@ -1052,6 +1049,14 @@ final class ActivityStack { next.idle = false; next.results = null; next.newIntents = null; + + if (next.isHomeActivity() && next.isNotResolverActivity()) { + ProcessRecord app = next.task.mActivities.get(0).app; + if (app != null && app != mService.mHomeProcess) { + mService.mHomeProcess = app; + } + } + if (next.nowVisible) { // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now. mStackSupervisor.dismissKeyguard(); @@ -1081,7 +1086,7 @@ final class ActivityStack { if (next == mLastScreenshotActivity) { invalidateLastScreenshot(); } - mReturningActivityOptions = null; + next.returningOptions = null; } private void setVisibile(ActivityRecord r, boolean visible) { @@ -1211,10 +1216,9 @@ final class ActivityStack { if (DEBUG_VISBILITY) Slog.v(TAG, "Skipping: already visible at " + r); r.stopFreezingScreenLocked(false); try { - if (mReturningActivityOptions != null && r == top && activityNdx > 0) { - ActivityRecord under = activities.get(activityNdx - 1); - under.app.thread.scheduleOnNewActivityOptions(under.appToken, - mReturningActivityOptions); + if (r.returningOptions != null) { + r.app.thread.scheduleOnNewActivityOptions(r.appToken, + r.returningOptions); } } catch(RemoteException e) { } @@ -1229,7 +1233,7 @@ final class ActivityStack { TAG, "Making visible and scheduling visibility: " + r); try { if (mTranslucentActivityWaiting != null) { - r.updateOptionsLocked(mReturningActivityOptions); + r.updateOptionsLocked(r.returningOptions); mUndrawnActivitiesBelowTopTranslucent.add(r); } setVisibile(r, true); @@ -1317,10 +1321,9 @@ final class ActivityStack { } } - void convertToTranslucent(ActivityRecord r, ActivityOptions options) { + void convertToTranslucent(ActivityRecord r) { mTranslucentActivityWaiting = r; mUndrawnActivitiesBelowTopTranslucent.clear(); - mReturningActivityOptions = options; mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT); } @@ -2067,6 +2070,8 @@ final class ActivityStack { final int rootActivityNdx = task.findEffectiveRootIndex(); for (int i = numActivities - 1; i > rootActivityNdx; --i ) { ActivityRecord target = activities.get(i); + if (target.frontOfTask) + break; final int flags = target.info.flags; final boolean finishOnTaskLaunch = @@ -2223,6 +2228,8 @@ final class ActivityStack { // Do not operate on or below the effective root Activity. for (int i = numActivities - 1; i > rootActivityNdx; --i) { ActivityRecord target = activities.get(i); + if (target.frontOfTask) + break; final int flags = target.info.flags; boolean finishOnTaskLaunch = (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0; @@ -2575,7 +2582,7 @@ final class ActivityStack { + " res=" + resultCode + " data=" + resultData); if (resultTo.userId != r.userId) { if (resultData != null) { - resultData.prepareToLeaveUser(r.userId); + resultData.setContentUserHint(r.userId); } } if (r.info.applicationInfo.uid > 0) { @@ -3789,7 +3796,9 @@ final class ActivityStack { if (r.app == app) { Slog.w(TAG, " Force finishing activity " + r.intent.getComponent().flattenToShortString()); - finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false); + // Force the destroy to skip right to removal. + r.app = null; + finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false); } } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 690b90a1f56e..48ed5ea6f120 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2176,7 +2176,7 @@ public final class ActivityStackSupervisor implements DisplayListener { //mWindowManager.dump(); if (enableScreen) { - mService.enableScreenAfterBoot(); + mService.postEnableScreenAfterBootLocked(); } if (activityRemoved) { diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index cdcc74b2685b..4e554eb2c4bb 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -424,11 +424,16 @@ public final class BroadcastQueue { Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { // Send the intent to the receiver asynchronously using one-way binder calls. - if (app != null && app.thread != null) { - // If we have an app thread, do the call through that so it is - // correctly ordered with other one-way calls. - app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, - data, extras, ordered, sticky, sendingUser, app.repProcState); + if (app != null) { + if (app.thread != null) { + // If we have an app thread, do the call through that so it is + // correctly ordered with other one-way calls. + app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, + data, extras, ordered, sticky, sendingUser, app.repProcState); + } else { + // Application has died. Receiver doesn't exist. + throw new RemoteException("app.thread must not be null"); + } } else { receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); @@ -670,6 +675,7 @@ public final class BroadcastQueue { // (local and remote) isn't kept in the mBroadcastHistory. r.resultTo = null; } catch (RemoteException e) { + r.resultTo = null; Slog.w(TAG, "Failure [" + mQueueName + "] sending broadcast result of " + r.intent, e); diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 10bdba060e80..403713d6d0f9 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -21,6 +21,7 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.net.NetworkMisc; import android.net.NetworkRequest; import android.os.Handler; import android.os.Messenger; @@ -44,6 +45,7 @@ public class NetworkAgentInfo { public NetworkCapabilities networkCapabilities; public int currentScore; public final NetworkMonitor networkMonitor; + public final NetworkMisc networkMisc; // The list of NetworkRequests being satisfied by this Network. public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>(); @@ -53,8 +55,8 @@ public class NetworkAgentInfo { public final AsyncChannel asyncChannel; public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, int netId, NetworkInfo info, - LinkProperties lp, NetworkCapabilities nc, int score, Context context, - Handler handler) { + LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, + NetworkMisc misc) { this.messenger = messenger; asyncChannel = ac; network = new Network(netId); @@ -63,6 +65,7 @@ public class NetworkAgentInfo { networkCapabilities = nc; currentScore = score; networkMonitor = new NetworkMonitor(context, handler, this); + networkMisc = misc; } public void addRequest(NetworkRequest networkRequest) { diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index d948942554e1..fa8626f10a4a 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -27,7 +27,6 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; -import android.net.IConnectivityManager; import android.net.INetworkStatsService; import android.net.InterfaceConfiguration; import android.net.LinkAddress; @@ -95,7 +94,6 @@ public class Tethering extends BaseNetworkObserver { private final INetworkManagementService mNMService; private final INetworkStatsService mStatsService; - private final IConnectivityManager mConnService; private Looper mLooper; private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces @@ -132,11 +130,10 @@ public class Tethering extends BaseNetworkObserver { // when RNDIS is enabled public Tethering(Context context, INetworkManagementService nmService, - INetworkStatsService statsService, IConnectivityManager connService, Looper looper) { + INetworkStatsService statsService, Looper looper) { mContext = context; mNMService = nmService; mStatsService = statsService; - mConnService = connService; mLooper = looper; mPublicSync = new Object(); @@ -176,6 +173,12 @@ public class Tethering extends BaseNetworkObserver { mDefaultDnsServers[1] = DNS_DEFAULT_SERVER2; } + // We can't do this once in the Tethering() constructor and cache the value, because the + // CONNECTIVITY_SERVICE is registered only after the Tethering() constructor has completed. + private ConnectivityManager getConnectivityManager() { + return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + } + void updateConfiguration() { String[] tetherableUsbRegexs = mContext.getResources().getStringArray( com.android.internal.R.array.config_tether_usb_regexs); @@ -367,11 +370,7 @@ public class Tethering extends BaseNetworkObserver { // TODO - move all private methods used only by the state machine into the state machine // to clarify what needs synchronized protection. private void sendTetherStateChangedBroadcast() { - try { - if (!mConnService.isTetheringSupported()) return; - } catch (RemoteException e) { - return; - } + if (!getConnectivityManager().isTetheringSupported()) return; ArrayList<String> availableList = new ArrayList<String>(); ArrayList<String> activeList = new ArrayList<String>(); @@ -1188,11 +1187,8 @@ public class Tethering extends BaseNetworkObserver { int result = PhoneConstants.APN_REQUEST_FAILED; String enableString = enableString(apnType); if (enableString == null) return false; - try { - result = mConnService.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - enableString, new Binder()); - } catch (Exception e) { - } + result = getConnectivityManager().startUsingNetworkFeature( + ConnectivityManager.TYPE_MOBILE, enableString); switch (result) { case PhoneConstants.APN_ALREADY_ACTIVE: case PhoneConstants.APN_REQUEST_STARTED: @@ -1213,12 +1209,8 @@ public class Tethering extends BaseNetworkObserver { // ignore pending renewal requests ++mCurrentConnectionSequence; if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) { - try { - mConnService.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - enableString(mMobileApnReserved)); - } catch (Exception e) { - return false; - } + getConnectivityManager().stopUsingNetworkFeature( + ConnectivityManager.TYPE_MOBILE, enableString(mMobileApnReserved)); mMobileApnReserved = ConnectivityManager.TYPE_NONE; } return true; @@ -1281,10 +1273,8 @@ public class Tethering extends BaseNetworkObserver { } for (Integer netType : mUpstreamIfaceTypes) { - NetworkInfo info = null; - try { - info = mConnService.getNetworkInfo(netType.intValue()); - } catch (RemoteException e) { } + NetworkInfo info = + getConnectivityManager().getNetworkInfo(netType.intValue()); if ((info != null) && info.isConnected()) { upType = netType.intValue(); break; @@ -1322,10 +1312,8 @@ public class Tethering extends BaseNetworkObserver { sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS); } } else { - LinkProperties linkProperties = null; - try { - linkProperties = mConnService.getLinkPropertiesForType(upType); - } catch (RemoteException e) { } + LinkProperties linkProperties = + getConnectivityManager().getLinkProperties(upType); if (linkProperties != null) { // Find the interface with the default IPv4 route. It may be the // interface described by linkProperties, or one of the interfaces diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 4b5a2cb0eb1a..0a8ca6aa1f58 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -17,6 +17,8 @@ package com.android.server.connectivity; import static android.Manifest.permission.BIND_VPN_SERVICE; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; import android.app.AppGlobals; import android.app.Notification; @@ -48,6 +50,7 @@ import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkMisc; import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.UidRange; @@ -106,6 +109,8 @@ public class Vpn { private String mPackage; private int mOwnerUID; private String mInterface; + private boolean mAllowIPv4; + private boolean mAllowIPv6; private Connection mConnection; private LegacyVpnRunner mLegacyVpnRunner; private PendingIntent mStatusIntent; @@ -306,6 +311,7 @@ public class Vpn { private void agentConnect() { LinkProperties lp = new LinkProperties(); lp.setInterfaceName(mInterface); + boolean hasDefaultRoute = false; for (RouteInfo route : mConfig.routes) { lp.addRoute(route); @@ -316,11 +322,19 @@ public class Vpn { } else { mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } + if (mConfig.dnsServers != null) { for (String dnsServer : mConfig.dnsServers) { - lp.addDnsServer(InetAddress.parseNumericAddress(dnsServer)); + InetAddress address = InetAddress.parseNumericAddress(dnsServer); + lp.addDnsServer(address); + if (address instanceof Inet4Address) { + mAllowIPv4 = true; + } else { + mAllowIPv6 = true; + } } } + // Concatenate search domains into a string. StringBuilder buffer = new StringBuilder(); if (mConfig.searchDomains != null) { @@ -329,12 +343,17 @@ public class Vpn { } } lp.setDomains(buffer.toString().trim()); + mNetworkInfo.setIsAvailable(true); mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); + + NetworkMisc networkMisc = new NetworkMisc(); + networkMisc.allowBypass = mConfig.allowBypass; + long token = Binder.clearCallingIdentity(); try { mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE, - mNetworkInfo, mNetworkCapabilities, lp, 0) { + mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) { public void unwanted() { // We are user controlled, not driven by NetworkRequest. }; @@ -342,6 +361,14 @@ public class Vpn { } finally { Binder.restoreCallingIdentity(token); } + + if (!mAllowIPv4) { + mNetworkAgent.blockAddressFamily(AF_INET); + } + if (!mAllowIPv6) { + mNetworkAgent.blockAddressFamily(AF_INET6); + } + addVpnUserLocked(mUserId); // If we are owner assign all Restricted Users to this VPN if (mUserId == UserHandle.USER_OWNER) { @@ -427,6 +454,8 @@ public class Vpn { NetworkAgent oldNetworkAgent = mNetworkAgent; mNetworkAgent = null; List<UidRange> oldUsers = mVpnUsers; + boolean oldAllowIPv4 = mAllowIPv4; + boolean oldAllowIPv6 = mAllowIPv6; // Configure the interface. Abort if any of these steps fails. ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); @@ -459,6 +488,9 @@ public class Vpn { // Set up forwarding and DNS rules. mVpnUsers = new ArrayList<UidRange>(); + mAllowIPv4 = mConfig.allowIPv4; + mAllowIPv6 = mConfig.allowIPv6; + agentConnect(); if (oldConnection != null) { @@ -487,12 +519,11 @@ public class Vpn { mVpnUsers = oldUsers; mNetworkAgent = oldNetworkAgent; mInterface = oldInterface; + mAllowIPv4 = oldAllowIPv4; + mAllowIPv6 = oldAllowIPv6; throw e; } Log.i(TAG, "Established by " + config.user + " on " + mInterface); - - // TODO: ensure that contract class eventually marks as connected - updateState(DetailedState.AUTHENTICATING, "establish"); return tun; } @@ -1173,6 +1204,8 @@ public class Vpn { // Now INetworkManagementEventObserver is watching our back. mInterface = mConfig.interfaze; mVpnUsers = new ArrayList<UidRange>(); + mAllowIPv4 = mConfig.allowIPv4; + mAllowIPv6 = mConfig.allowIPv6; agentConnect(); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 2737646625ee..b9acea583829 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1367,7 +1367,7 @@ public final class DisplayManagerService extends SystemService { } if (mContext.checkCallingPermission( android.Manifest.permission.CAPTURE_VIDEO_OUTPUT) - != PackageManager.PERMISSION_GRANTED) { + == PackageManager.PERMISSION_GRANTED) { return true; } return canProjectSecureVideo(projection); @@ -1385,7 +1385,7 @@ public final class DisplayManagerService extends SystemService { } return mContext.checkCallingPermission( android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT) - != PackageManager.PERMISSION_GRANTED; + == PackageManager.PERMISSION_GRANTED; } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 09221a3e9c1d..d0e4b33fab7e 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -566,8 +566,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Apply dimming by at least some minimum amount when user activity // timeout is about to expire. if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) { - brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION, - mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum); + if (brightness > mScreenBrightnessRangeMinimum) { + brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION, + mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum); + } if (!mAppliedDimming) { slowChange = false; } diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index 107a6f687406..b89430452846 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -45,7 +45,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.service.dreams.DreamManagerInternal; import android.service.dreams.DreamService; -import android.service.dreams.IDozeHardware; import android.service.dreams.IDreamManager; import android.text.TextUtils; import android.util.Slog; @@ -75,7 +74,6 @@ public final class DreamManagerService extends SystemService { private final PowerManager mPowerManager; private final PowerManagerInternal mPowerManagerInternal; private final PowerManager.WakeLock mDozeWakeLock; - private final McuHal mMcuHal; // synchronized on self private Binder mCurrentDreamToken; private ComponentName mCurrentDreamName; @@ -86,7 +84,6 @@ public final class DreamManagerService extends SystemService { private boolean mCurrentDreamIsWaking; private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN; private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; - private DozeHardwareWrapper mCurrentDreamDozeHardware; public DreamManagerService(Context context) { super(context); @@ -97,11 +94,6 @@ public final class DreamManagerService extends SystemService { mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mPowerManagerInternal = getLocalService(PowerManagerInternal.class); mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG); - - mMcuHal = McuHal.open(); - if (mMcuHal != null) { - mMcuHal.reset(); - } } @Override @@ -130,9 +122,6 @@ public final class DreamManagerService extends SystemService { private void dumpInternal(PrintWriter pw) { pw.println("DREAM MANAGER (dumpsys dreams)"); pw.println(); - - pw.println("mMcuHal=" + mMcuHal); - pw.println(); pw.println("mCurrentDreamToken=" + mCurrentDreamToken); pw.println("mCurrentDreamName=" + mCurrentDreamName); pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId); @@ -143,7 +132,6 @@ public final class DreamManagerService extends SystemService { pw.println("mCurrentDreamDozeScreenState=" + Display.stateToString(mCurrentDreamDozeScreenState)); pw.println("mCurrentDreamDozeScreenBrightness=" + mCurrentDreamDozeScreenBrightness); - pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware); pw.println("getDozeComponent()=" + getDozeComponent()); pw.println(); @@ -259,17 +247,6 @@ public final class DreamManagerService extends SystemService { } } - private IDozeHardware getDozeHardwareInternal(IBinder token) { - synchronized (mLock) { - if (mCurrentDreamToken == token && mCurrentDreamCanDoze - && mCurrentDreamDozeHardware == null && mMcuHal != null) { - mCurrentDreamDozeHardware = new DozeHardwareWrapper(); - return mCurrentDreamDozeHardware; - } - return null; - } - } - private ComponentName chooseDreamForUser(boolean doze, int userId) { if (doze) { ComponentName dozeComponent = getDozeComponent(); @@ -420,10 +397,6 @@ public final class DreamManagerService extends SystemService { } mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN; mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; - if (mCurrentDreamDozeHardware != null) { - mCurrentDreamDozeHardware.release(); - mCurrentDreamDozeHardware = null; - } } private void checkPermission(String permission) { @@ -642,21 +615,6 @@ public final class DreamManagerService extends SystemService { Binder.restoreCallingIdentity(ident); } } - - @Override // Binder call - public IDozeHardware getDozeHardware(IBinder token) { - // Requires no permission, called by Dream from an arbitrary process. - if (token == null) { - throw new IllegalArgumentException("token must not be null"); - } - - final long ident = Binder.clearCallingIdentity(); - try { - return getDozeHardwareInternal(token); - } finally { - Binder.restoreCallingIdentity(ident); - } - } } private final class LocalService extends DreamManagerInternal { @@ -676,40 +634,6 @@ public final class DreamManagerService extends SystemService { } } - private final class DozeHardwareWrapper extends IDozeHardware.Stub { - private boolean mReleased; - - public void release() { - synchronized (mMcuHal) { - if (!mReleased) { - mReleased = true; - mMcuHal.reset(); - } - } - } - - @Override // Binder call - public byte[] sendMessage(String msg, byte[] arg) { - if (msg == null) { - throw new IllegalArgumentException("msg must not be null"); - } - - final long ident = Binder.clearCallingIdentity(); - try { - synchronized (mMcuHal) { - if (mReleased) { - Slog.w(TAG, "Ignoring message to MCU HAL because the dream " - + "has already ended: " + msg); - return null; - } - return mMcuHal.sendMessage(msg, arg); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - private final Runnable mSystemPropertiesChanged = new Runnable() { @Override public void run() { diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java deleted file mode 100644 index 1dc79c7bf0e6..000000000000 --- a/services/core/java/com/android/server/dreams/McuHal.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.dreams; - -import android.service.dreams.DozeHardware; - -/** - * Provides access to the low-level microcontroller hardware abstraction layer. - */ -final class McuHal { - private final long mPtr; - - private static native long nativeOpen(); - private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg); - - private McuHal(long ptr) { - mPtr = ptr; - } - - public static McuHal open() { - long ptr = nativeOpen(); - return ptr != 0 ? new McuHal(ptr) : null; - } - - public void reset() { - sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF); - } - - public byte[] sendMessage(String msg, byte[] arg) { - return nativeSendMessage(mPtr, msg, arg); - } -} diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java index 432424bb7954..f3d570e27b5f 100644 --- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java +++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java @@ -23,6 +23,8 @@ import android.hardware.hdmi.HdmiControlManager; import android.os.RemoteException; import android.util.Slog; +import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; + /** * Handles CEC command <Active Source>. * <p> @@ -54,44 +56,45 @@ final class ActiveSourceHandler { /** * Handles the incoming active source command. * - * @param activeAddress logical address of the device to be the active source - * @param activePath routing path of the device to be the active source + * @param newActive new active source information */ - void process(int activeAddress, int activePath) { + void process(ActiveSource newActive) { // Seq #17 HdmiCecLocalDeviceTv tv = mSource; - if (getSourcePath() == activePath && tv.getActiveSource() == getSourceAddress()) { + ActiveSource activeSource = tv.getActiveSource(); + if (activeSource.equals(newActive)) { invokeCallback(HdmiControlManager.RESULT_SUCCESS); return; } - HdmiCecDeviceInfo device = mService.getDeviceInfo(activeAddress); + HdmiCecDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress); if (device == null) { - tv.startNewDeviceAction(activeAddress, activePath); + tv.startNewDeviceAction(newActive); } - int currentActive = tv.getActiveSource(); - int currentPath = tv.getActivePath(); + ActiveSource current = tv.getActiveSource(); if (!tv.isProhibitMode()) { - tv.updateActiveSource(activeAddress, activePath); - if (currentActive != activeAddress && currentPath != activePath) { - tv.updateActivePortId(mService.pathToPortId(activePath)); + tv.updateActiveSource(newActive); + if (!current.equals(newActive)) { + boolean notifyInputChange = (mCallback == null); + tv.updateActiveInput(newActive.physicalAddress, notifyInputChange); } invokeCallback(HdmiControlManager.RESULT_SUCCESS); } else { // TV is in a mode that should keep its current source/input from // being changed for its operation. Reclaim the active source // or switch the port back to the one used for the current mode. - if (currentActive == getSourceAddress()) { - HdmiCecMessage activeSource = - HdmiCecMessageBuilder.buildActiveSource(currentActive, currentPath); - mService.sendCecCommand(activeSource); - tv.updateActiveSource(currentActive, currentPath); + if (current.logicalAddress == getSourceAddress()) { + HdmiCecMessage activeSourceCommand = HdmiCecMessageBuilder.buildActiveSource( + current.logicalAddress, current.physicalAddress); + mService.sendCecCommand(activeSourceCommand); + tv.updateActiveSource(current); invokeCallback(HdmiControlManager.RESULT_SUCCESS); } else { HdmiCecMessage routingChange = HdmiCecMessageBuilder.buildRoutingChange( - getSourceAddress(), activePath, currentPath); + getSourceAddress(), newActive.physicalAddress, current.physicalAddress); mService.sendCecCommand(routingChange); - tv.addAndStartAction(new RoutingControlAction(tv, currentPath, true, mCallback)); + tv.addAndStartAction( + new RoutingControlAction(tv, current.physicalAddress, true, mCallback)); } } } diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java index a75b4854684d..86e14e12193b 100644 --- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java @@ -69,6 +69,7 @@ final class DeviceDiscoveryAction extends FeatureAction { private final int mLogicalAddress; private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS; + private int mPortId = Constants.INVALID_PORT_ID; private int mVendorId = Constants.UNKNOWN_VENDOR_ID; private String mDisplayName = ""; private int mDeviceType = HdmiCecDeviceInfo.DEVICE_INACTIVE; @@ -78,8 +79,8 @@ final class DeviceDiscoveryAction extends FeatureAction { } private HdmiCecDeviceInfo toHdmiCecDeviceInfo() { - return new HdmiCecDeviceInfo(mLogicalAddress, mPhysicalAddress, mDeviceType, mVendorId, - mDisplayName); + return new HdmiCecDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType, + mVendorId, mDisplayName); } } @@ -252,12 +253,17 @@ final class DeviceDiscoveryAction extends FeatureAction { byte params[] = cmd.getParams(); current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params); + current.mPortId = getPortId(current.mPhysicalAddress); current.mDeviceType = params[2] & 0xFF; increaseProcessedDeviceCount(); checkAndProceedStage(); } + private int getPortId(int physicalAddress) { + return tv().getPortId(physicalAddress); + } + private void handleSetOsdName(HdmiCecMessage cmd) { Preconditions.checkState(mProcessedDeviceCount < mDevices.size()); diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java index d4fffcf45c26..018b34d3ce54 100644 --- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -23,6 +23,7 @@ import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; +import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; /** @@ -130,10 +131,10 @@ final class DeviceSelectAction extends FeatureAction { return false; case STATE_WAIT_FOR_ACTIVE_SOURCE: if (opcode == Constants.MESSAGE_ACTIVE_SOURCE) { - int activePath = HdmiUtils.twoBytesToInt(params); + int physicalAddress = HdmiUtils.twoBytesToInt(params); ActiveSourceHandler .create((HdmiCecLocalDeviceTv) localDevice(), mCallback) - .process(cmd.getSource(), activePath); + .process(ActiveSource.of(cmd.getSource(), physicalAddress)); finish(); return true; } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index dbcdfc01e6e4..40eb3e443938 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -49,9 +49,41 @@ abstract class HdmiCecLocalDevice { protected int mPreferredAddress; protected HdmiCecDeviceInfo mDeviceInfo; + static class ActiveSource { + int logicalAddress; + int physicalAddress; + + public ActiveSource(int logical, int physical) { + logicalAddress = logical; + physicalAddress = physical; + } + public static ActiveSource of(int logical, int physical) { + return new ActiveSource(logical, physical); + } + public boolean isValid() { + return HdmiUtils.isValidAddress(logicalAddress); + } + public boolean equals(int logical, int physical) { + return logicalAddress == logical && physicalAddress == physical; + } + @Override + public boolean equals(Object obj) { + if (obj instanceof ActiveSource) { + ActiveSource that = (ActiveSource) obj; + return that.logicalAddress == logicalAddress && + that.physicalAddress == physicalAddress; + } + return false; + } + @Override + public int hashCode() { + return logicalAddress * 29 + physicalAddress; + } + } // Logical address of the active source. @GuardedBy("mLock") - private int mActiveSource; + protected final ActiveSource mActiveSource = + new ActiveSource(-1, Constants.INVALID_PHYSICAL_ADDRESS); // Active routing path. Physical address of the active source but not all the time, such as // when the new active source does not claim itself to be one. Note that we don't keep @@ -549,15 +581,24 @@ abstract class HdmiCecLocalDevice { return mService.isConnectedToArcPort(path); } - int getActiveSource() { + ActiveSource getActiveSource() { synchronized (mLock) { return mActiveSource; } } - void setActiveSource(int source) { + void setActiveSource(ActiveSource newActive) { + setActiveSource(newActive.logicalAddress, newActive.physicalAddress); + } + + void setActiveSource(HdmiCecDeviceInfo info) { + setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress()); + } + + void setActiveSource(int logicalAddress, int physicalAddress) { synchronized (mLock) { - mActiveSource = source; + mActiveSource.logicalAddress = logicalAddress; + mActiveSource.physicalAddress = physicalAddress; } } @@ -596,13 +637,6 @@ abstract class HdmiCecLocalDevice { } } - void updateActiveDevice(int logicalAddress, int physicalAddress) { - synchronized (mLock) { - mActiveSource = logicalAddress; - mActiveRoutingPath = physicalAddress; - } - } - @ServiceThreadOnly HdmiCecMessageCache getCecMessageCache() { assertRunOnServiceThread(); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index bbecafa8f779..f93d20f02005 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -16,10 +16,18 @@ package com.android.server.hdmi; +import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CEC_DISABLED; +import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION; +import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN; +import static android.hardware.hdmi.HdmiControlManager.TIME_RECORDING_RESULT_EXTRA_CEC_DISABLED; +import static android.hardware.hdmi.HdmiControlManager.TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION; +import static android.hardware.hdmi.HdmiControlManager.TIME_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE; + import android.content.Intent; import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiRecordSources; +import android.hardware.hdmi.HdmiTimerRecordSources; import android.hardware.hdmi.IHdmiControlCallback; import android.media.AudioManager; import android.media.AudioSystem; @@ -47,7 +55,7 @@ import java.util.Locale; final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { private static final String TAG = "HdmiCecLocalDeviceTv"; - // Whether ARC is available or not. "true" means that ARC is estabilished between TV and + // Whether ARC is available or not. "true" means that ARC is established between TV and // AVR as audio receiver. @ServiceThreadOnly private boolean mArcEstablished = false; @@ -139,12 +147,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (targetAddress == Constants.ADDR_INTERNAL) { handleSelectInternalSource(); // Switching to internal source is always successful even when CEC control is disabled. - setActiveSource(targetAddress); + setActiveSource(targetAddress, mService.getPhysicalAddress()); invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); return; } if (!mService.isControlEnabled()) { - setActiveSource(targetAddress); + HdmiCecDeviceInfo info = getDeviceInfo(targetAddress); + if (info != null) { + setActiveSource(info); + } invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); return; } @@ -161,7 +172,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { private void handleSelectInternalSource() { assertRunOnServiceThread(); // Seq #18 - if (mService.isControlEnabled() && getActiveSource() != mAddress) { + if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) { updateActiveSource(mAddress, mService.getPhysicalAddress()); // TODO: Check if this comes from <Text/Image View On> - if true, do nothing. HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( @@ -171,16 +182,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @ServiceThreadOnly - void updateActiveSource(int activeSource, int activePath) { + void updateActiveSource(int logicalAddress, int physicalAddress) { + assertRunOnServiceThread(); + updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress)); + } + + @ServiceThreadOnly + void updateActiveSource(ActiveSource newActive) { assertRunOnServiceThread(); // Seq #14 - if (activeSource == getActiveSource() && activePath == getActivePath()) { + if (mActiveSource.equals(newActive)) { return; } - setActiveSource(activeSource); - setActivePath(activePath); - if (getDeviceInfo(activeSource) != null && activeSource != mAddress) { - if (mService.pathToPortId(activePath) == getActivePortId()) { + setActiveSource(newActive); + int logicalAddress = newActive.logicalAddress; + if (getDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) { + if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) { setPrevPortId(getActivePortId()); } // TODO: Show the OSD banner related to the new active source device. @@ -190,6 +207,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } + int getPortId(int physicalAddress) { + return mService.pathToPortId(physicalAddress); + } + /** * Returns the previous port id kept to handle input switching on <Inactive Source>. */ @@ -210,16 +231,26 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @ServiceThreadOnly - void updateActivePortId(int portId) { + void updateActiveInput(int path, boolean notifyInputChange) { assertRunOnServiceThread(); // Seq #15 + int portId = mService.pathToPortId(path); if (portId == getActivePortId()) { return; } + setActivePath(path); setPrevPortId(portId); - // TODO: Actually switch the physical port here. Handle PAP/PIP as well. - // Show OSD port change banner - mService.invokeInputChangeListener(getActiveSource()); + // TODO: Handle PAP/PIP case. + // Show OSD port change banner + if (notifyInputChange) { + ActiveSource activeSource = getActiveSource(); + HdmiCecDeviceInfo info = getDeviceInfo(activeSource.logicalAddress); + if (info == null) { + info = new HdmiCecDeviceInfo(Constants.ADDR_INVALID, path, portId, + HdmiCecDeviceInfo.DEVICE_RESERVED, 0, null); + } + mService.invokeInputChangeListener(info); + } } @ServiceThreadOnly @@ -230,26 +261,25 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); return; } + if (portId == getActivePortId()) { + invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); + return; + } + setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS); if (!mService.isControlEnabled()) { setActivePortId(portId); invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); return; } - if (portId == getActivePortId()) { - invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); - return; - } - setActivePortId(portId); // TODO: Return immediately if the operation is triggered by <Text/Image View On> - // and this is the first notification about the active input after power-on - // (switch to HDMI didn't happen so far but is expected to happen soon). - removeAction(RoutingControlAction.class); - - int oldPath = mService.portIdToPath(mService.portIdToPath(getActivePortId())); + // and this is the first notification about the active input after power-on + // (switch to HDMI didn't happen so far but is expected to happen soon). + int oldPath = mService.portIdToPath(getActivePortId()); int newPath = mService.portIdToPath(portId); HdmiCecMessage routingChange = HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath); mService.sendCecCommand(routingChange); + removeAction(RoutingControlAction.class); addAndStartAction(new RoutingControlAction(this, newPath, false, callback)); } @@ -272,7 +302,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { action.get(0).processKeyEvent(keyCode, isPressed); } else { if (isPressed) { - addAndStartAction(new SendKeyAction(this, getActiveSource(), keyCode)); + int logicalAddress = getActiveSource().logicalAddress; + addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode)); } else { Slog.w(TAG, "Discard key release event"); } @@ -294,12 +325,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleActiveSource(HdmiCecMessage message) { assertRunOnServiceThread(); - int address = message.getSource(); - int path = HdmiUtils.twoBytesToInt(message.getParams()); - if (getDeviceInfo(address) == null) { - handleNewDeviceAtTheTailOfActivePath(path); + int logicalAddress = message.getSource(); + int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); + if (getDeviceInfo(logicalAddress) == null) { + handleNewDeviceAtTheTailOfActivePath(physicalAddress); } else { - ActiveSourceHandler.create(this, null).process(address, path); + ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress); + ActiveSourceHandler.create(this, null).process(activeSource); } return true; } @@ -311,7 +343,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // Seq #10 // Ignore <Inactive Source> from non-active source device. - if (getActiveSource() != message.getSource()) { + if (getActiveSource().logicalAddress != message.getSource()) { return true; } if (isProhibitMode()) { @@ -330,7 +362,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } // TODO: Switch the TV freeze mode off - setActivePortId(portId); doManualPortSwitching(portId, null); setPrevPortId(Constants.INVALID_PORT_ID); } @@ -342,7 +373,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { protected boolean handleRequestActiveSource(HdmiCecMessage message) { assertRunOnServiceThread(); // Seq #19 - if (mAddress == getActiveSource()) { + if (mAddress == getActiveSource().logicalAddress) { mService.sendCecCommand( HdmiCecMessageBuilder.buildActiveSource(mAddress, getActivePath())); } @@ -380,11 +411,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (!isInDeviceList(path, address)) { handleNewDeviceAtTheTailOfActivePath(path); } - startNewDeviceAction(address, path); + startNewDeviceAction(ActiveSource.of(address, path)); return true; } - void startNewDeviceAction(int address, int path) { + void startNewDeviceAction(ActiveSource activeSource) { for (NewDeviceAction action : getActions(NewDeviceAction.class)) { // If there is new device action which has the same logical address and path // ignore new request. @@ -394,12 +425,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // in. However, TV can detect a new device from HotPlugDetectionAction, // which sends <Give Physical Address> to the source for newly detected // device. - if (action.isActionOf(address, path)) { + if (action.isActionOf(activeSource)) { return; } } - addAndStartAction(new NewDeviceAction(this, address, path)); + addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress, + activeSource.physicalAddress)); } private void handleNewDeviceAtTheTailOfActivePath(int path) { @@ -512,8 +544,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } addCecDevice(new HdmiCecDeviceInfo(deviceInfo.getLogicalAddress(), - deviceInfo.getPhysicalAddress(), deviceInfo.getDeviceType(), - deviceInfo.getVendorId(), osdName)); + deviceInfo.getPhysicalAddress(), deviceInfo.getPortId(), + deviceInfo.getDeviceType(), deviceInfo.getVendorId(), osdName)); return true; } @@ -819,7 +851,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // Assumes only one OneTouchRecordAction. OneTouchRecordAction action = actions.get(0); if (action.getRecorderAddress() != message.getSource()) { - displayOsd(HdmiControlManager.MESSAGE_NO_RECORDING_PREVIOUS_RECORDING_IN_PROGRESS); + announceOneTouchRecordResult( + HdmiControlManager.ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS); } return super.handleRecordTvScreen(message); } @@ -830,6 +863,14 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return true; } + void announceOneTouchRecordResult(int result) { + mService.invokeOneTouchRecordResult(result); + } + + void announceTimerRecordingResult(int result) { + mService.invokeTimerRecordingResult(result); + } + private boolean isMessageForSystemAudio(HdmiCecMessage message) { if (message.getSource() != Constants.ADDR_AUDIO_SYSTEM || message.getDestination() != Constants.ADDR_TV @@ -1241,16 +1282,19 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { assertRunOnServiceThread(); if (!mService.isControlEnabled()) { Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); + announceOneTouchRecordResult(ONE_TOUCH_RECORD_CEC_DISABLED); return; } if (!checkRecorder(recorderAddress)) { Slog.w(TAG, "Invalid recorder address:" + recorderAddress); + announceOneTouchRecordResult(ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); return; } if (!checkRecordSource(recordSource)) { Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); + announceOneTouchRecordResult(ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN); return; } @@ -1264,11 +1308,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { assertRunOnServiceThread(); if (!mService.isControlEnabled()) { Slog.w(TAG, "Can not stop one touch record. CEC control is disabled."); + announceOneTouchRecordResult(ONE_TOUCH_RECORD_CEC_DISABLED); return; } if (!checkRecorder(recorderAddress)) { Slog.w(TAG, "Invalid recorder address:" + recorderAddress); + announceOneTouchRecordResult(ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); return; } @@ -1292,8 +1338,35 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) { assertRunOnServiceThread(); + if (!mService.isControlEnabled()) { + Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); + announceTimerRecordingResult(TIME_RECORDING_RESULT_EXTRA_CEC_DISABLED); + return; + } - // TODO: implement this. + if (!checkRecorder(recorderAddress)) { + Slog.w(TAG, "Invalid recorder address:" + recorderAddress); + announceTimerRecordingResult( + TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION); + return; + } + + if (!checkTimerRecordingSource(sourceType, recordSource)) { + Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); + announceTimerRecordingResult( + TIME_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE); + return; + } + + addAndStartAction( + new TimerRecordingAction(this, recorderAddress, sourceType, recordSource)); + Slog.i(TAG, "Start [Timer Recording]-Target:" + recorderAddress + ", SourceType:" + + sourceType + ", RecordSource:" + Arrays.toString(recordSource)); + } + + private boolean checkTimerRecordingSource(int sourceType, byte[] recordSource) { + return (recordSource != null) + && HdmiTimerRecordSources.checkTimerRecordSource(sourceType, recordSource); } @ServiceThreadOnly diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java index 79f196481266..0855bfa1a704 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java @@ -478,6 +478,78 @@ public class HdmiCecMessageBuilder { return buildCommand(src, dest, Constants.MESSAGE_RECORD_OFF); } + /** + * Build <Set Digital Timer> command. + * + * @param src source address of command + * @param dest destination address of command + * @param params byte array of timing information and digital service information to be recorded + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildSetDigitalTimer(int src, int dest, byte[] params) { + return buildCommand(src, dest, Constants.MESSAGE_SET_DIGITAL_TIMER, params); + } + + /** + * Build <Set Analogue Timer> command. + * + * @param src source address of command + * @param dest destination address of command + * @param params byte array of timing information and analog service information to be recorded + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildSetAnalogueTimer(int src, int dest, byte[] params) { + return buildCommand(src, dest, Constants.MESSAGE_SET_ANALOG_TIMER, params); + } + + /** + * Build <Set External Timer> command. + * + * @param src source address of command + * @param dest destination address of command + * @param params byte array of timing information and external source information to be recorded + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildSetExternalTimer(int src, int dest, byte[] params) { + return buildCommand(src, dest, Constants.MESSAGE_SET_EXTERNAL_TIMER, params); + } + + /** + * Build <Clear Digital Timer> command. + * + * @param src source address of command + * @param dest destination address of command + * @param params byte array of timing information and digital service information to be cleared + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildClearDigitalTimer(int src, int dest, byte[] params) { + return buildCommand(src, dest, Constants.MESSAGE_CLEAR_DIGITAL_TIMER, params); + } + + /** + * Build <Clear Analog Timer> command. + * + * @param src source address of command + * @param dest destination address of command + * @param params byte array of timing information and analog service information to be cleared + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildClearAnalogueTimer(int src, int dest, byte[] params) { + return buildCommand(src, dest, Constants.MESSAGE_CLEAR_ANALOG_TIMER, params); + } + + /** + * Build <Clear Digital Timer> command. + * + * @param src source address of command + * @param dest destination address of command + * @param params byte array of timing information and external source information to be cleared + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildClearExternalTimer(int src, int dest, byte[] params) { + return buildCommand(src, dest, Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, params); + } + /***** Please ADD new buildXXX() methods above. ******/ /** diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java index c9330c51e733..d491ac295b06 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java @@ -243,12 +243,17 @@ public final class HdmiCecMessageValidator { } private boolean isValidPhysicalAddress(byte[] params, int offset) { + // TODO: Add more logic like validating 1.0.1.0. + + if (!mService.isTvDevice()) { + // If the device is not TV, we can't convert path to port-id, so stop here. + return true; + } int path = HdmiUtils.twoBytesToInt(params, offset); int portId = mService.pathToPortId(path); if (portId == Constants.INVALID_PORT_ID) { return false; } - // TODO: Add more logic like validating 1.0.1.0. return true; } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 76722325a182..37c297b818be 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -32,7 +32,7 @@ import android.hardware.hdmi.IHdmiControlService; import android.hardware.hdmi.IHdmiDeviceEventListener; import android.hardware.hdmi.IHdmiHotplugEventListener; import android.hardware.hdmi.IHdmiInputChangeListener; -import android.hardware.hdmi.IHdmiRecordRequestListener; +import android.hardware.hdmi.IHdmiRecordListener; import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; import android.hardware.hdmi.IHdmiVendorCommandListener; import android.media.AudioManager; @@ -45,6 +45,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings.Global; +import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; @@ -160,10 +161,10 @@ public final class HdmiControlService extends SystemService { private InputChangeListenerRecord mInputChangeListenerRecord; @GuardedBy("mLock") - private IHdmiRecordRequestListener mRecordRequestListener; + private IHdmiRecordListener mRecordListener; @GuardedBy("mLock") - private HdmiRecordRequestListenerRecord mRecordRequestListenerRecord; + private HdmiRecordListenerRecord mRecordListenerRecord; // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol // handling will be disabled and no request will be handled. @@ -197,6 +198,12 @@ public final class HdmiControlService extends SystemService { // from being modified. private List<HdmiPortInfo> mPortInfo; + // Map from path(physical address) to port ID. + private SparseIntArray mPortIdMap = new SparseIntArray(); + + // Map from port ID to HdmiPortInfo. + private SparseArray<HdmiPortInfo> mPortInfoMap = new SparseArray<>(); + private HdmiCecMessageValidator mMessageValidator; private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver(); @@ -238,7 +245,7 @@ public final class HdmiControlService extends SystemService { if (mMhlController == null) { Slog.i(TAG, "Device does not support MHL-control."); } - mPortInfo = initPortInfo(); + initPortInfo(); mMessageValidator = new HdmiCecMessageValidator(this); publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); @@ -318,7 +325,7 @@ public final class HdmiControlService extends SystemService { // Initialize HDMI port information. Combine the information from CEC and MHL HAL and // keep them in one place. @ServiceThreadOnly - private List<HdmiPortInfo> initPortInfo() { + private void initPortInfo() { assertRunOnServiceThread(); HdmiPortInfo[] cecPortInfo = null; @@ -328,7 +335,12 @@ public final class HdmiControlService extends SystemService { cecPortInfo = mCecController.getPortInfos(); } if (cecPortInfo == null) { - return Collections.emptyList(); + return; + } + + for (HdmiPortInfo info : cecPortInfo) { + mPortIdMap.put(info.getAddress(), info.getId()); + mPortInfoMap.put(info.getId(), info); } HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0]; @@ -337,27 +349,24 @@ public final class HdmiControlService extends SystemService { // mhlPortInfo = mMhlController.getPortInfos(); } - // Use the id (port number) to find the matched info between CEC and MHL to combine them - // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found. - ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); - for (int i = 0; i < cecPortInfo.length; ++i) { - HdmiPortInfo cec = cecPortInfo[i]; - int id = cec.getId(); - boolean mhlInfoFound = false; - for (HdmiPortInfo mhl : mhlPortInfo) { - if (id == mhl.getId()) { - result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(), - cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported())); - mhlInfoFound = true; - break; - } - } - if (!mhlInfoFound) { - result.add(cec); + ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); + for (HdmiPortInfo info : mhlPortInfo) { + if (info.isMhlSupported()) { + mhlSupportedPorts.add(info.getId()); } } - return Collections.unmodifiableList(result); + // Build HDMI port info list with CEC port info plus MHL supported flag. + ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); + for (HdmiPortInfo info : cecPortInfo) { + if (mhlSupportedPorts.contains(info.getId())) { + result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), + info.isCecSupported(), true, info.isArcSupported())); + } else { + result.add(info); + } + } + mPortInfo = Collections.unmodifiableList(result); } /** @@ -366,22 +375,19 @@ public final class HdmiControlService extends SystemService { * @param portId HDMI port id * @return {@link HdmiPortInfo} for the given port */ + @ServiceThreadOnly HdmiPortInfo getPortInfo(int portId) { - // mPortInfo is an unmodifiable list and the only reference to its inner list. - // No lock is necessary. - for (HdmiPortInfo info : mPortInfo) { - if (portId == info.getId()) { - return info; - } - } - return null; + assertRunOnServiceThread(); + return mPortInfoMap.get(portId, null); } /** * Returns the routing path (physical address) of the HDMI port for the given * port id. */ + @ServiceThreadOnly int portIdToPath(int portId) { + assertRunOnServiceThread(); HdmiPortInfo portInfo = getPortInfo(portId); if (portInfo == null) { Slog.e(TAG, "Cannot find the port info: " + portId); @@ -396,23 +402,17 @@ public final class HdmiControlService extends SystemService { * the port id to be returned is the ID associated with the port address * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. */ + @ServiceThreadOnly int pathToPortId(int path) { + assertRunOnServiceThread(); int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; - for (HdmiPortInfo info : mPortInfo) { - if (portAddress == info.getAddress()) { - return info.getId(); - } - } - return Constants.INVALID_PORT_ID; + return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); } + @ServiceThreadOnly boolean isValidPortId(int portId) { - for (HdmiPortInfo info : mPortInfo) { - if (portId == info.getId()) { - return true; - } - } - return false; + assertRunOnServiceThread(); + return getPortInfo(portId) != null; } /** @@ -468,12 +468,12 @@ public final class HdmiControlService extends SystemService { /** * Whether a device of the specified physical address is connected to ARC enabled port. */ + @ServiceThreadOnly boolean isConnectedToArcPort(int physicalAddress) { - for (HdmiPortInfo portInfo : mPortInfo) { - if (hasSameTopPort(portInfo.getAddress(), physicalAddress) - && portInfo.isArcSupported()) { - return true; - } + assertRunOnServiceThread(); + int portId = mPortIdMap.get(physicalAddress); + if (portId != Constants.INVALID_PORT_ID) { + return mPortInfoMap.get(portId).isArcSupported(); } return false; } @@ -622,7 +622,8 @@ public final class HdmiControlService extends SystemService { // TODO: find better name instead of model name. String displayName = Build.MODEL; return new HdmiCecDeviceInfo(logicalAddress, - getPhysicalAddress(), deviceType, getVendorId(), displayName); + getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, + getVendorId(), displayName); } // Record class that monitors the event of the caller of being killed. Used to clean up @@ -692,11 +693,11 @@ public final class HdmiControlService extends SystemService { } } - private class HdmiRecordRequestListenerRecord implements IBinder.DeathRecipient { + private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { @Override public void binderDied() { synchronized (mLock) { - mRecordRequestListener = null; + mRecordListener = null; } } } @@ -723,6 +724,10 @@ public final class HdmiControlService extends SystemService { runOnServiceThread(new Runnable() { @Override public void run() { + if (callback == null) { + Slog.e(TAG, "Callback cannot be null"); + return; + } HdmiCecLocalDeviceTv tv = tv(); if (tv == null) { Slog.w(TAG, "Local tv device not available"); @@ -740,6 +745,10 @@ public final class HdmiControlService extends SystemService { runOnServiceThread(new Runnable() { @Override public void run() { + if (callback == null) { + Slog.e(TAG, "Callback cannot be null"); + return; + } HdmiCecLocalDeviceTv tv = tv(); if (tv == null) { Slog.w(TAG, "Local tv device not available"); @@ -980,10 +989,6 @@ public final class HdmiControlService extends SystemService { } } - private boolean isTvDevice() { - return tv() != null; - } - @Override public void setProhibitMode(final boolean enabled) { enforceAccessPermission(); @@ -1027,11 +1032,11 @@ public final class HdmiControlService extends SystemService { } } }); - } + } @Override - public void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener) { - HdmiControlService.this.setOneTouchRecordRequestListener(listener); + public void setHdmiRecordListener(IHdmiRecordListener listener) { + HdmiControlService.this.setHdmiRecordListener(listener); } @Override @@ -1221,12 +1226,11 @@ public final class HdmiControlService extends SystemService { } } - void invokeInputChangeListener(int activeAddress) { + void invokeInputChangeListener(HdmiCecDeviceInfo info) { synchronized (mLock) { if (mInputChangeListener != null) { - HdmiCecDeviceInfo activeSource = getDeviceInfo(activeAddress); try { - mInputChangeListener.onChanged(activeSource); + mInputChangeListener.onChanged(info); } catch (RemoteException e) { Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); } @@ -1234,32 +1238,55 @@ public final class HdmiControlService extends SystemService { } } - private void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener) { + private void setHdmiRecordListener(IHdmiRecordListener listener) { synchronized (mLock) { - mRecordRequestListenerRecord = new HdmiRecordRequestListenerRecord(); + mRecordListenerRecord = new HdmiRecordListenerRecord(); try { - listener.asBinder().linkToDeath(mRecordRequestListenerRecord, 0); + listener.asBinder().linkToDeath(mRecordListenerRecord, 0); } catch (RemoteException e) { - Slog.w(TAG, "Listener already died", e); - return; + Slog.w(TAG, "Listener already died.", e); } - mRecordRequestListener = listener; + mRecordListener = listener; } } byte[] invokeRecordRequestListener(int recorderAddress) { synchronized (mLock) { - try { - if (mRecordRequestListener != null) { - return mRecordRequestListener.onRecordRequestReceived(recorderAddress); + if (mRecordListener != null) { + try { + return mRecordListener.getOneTouchRecordSource(recorderAddress); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to start record.", e); } - } catch (RemoteException e) { - Slog.w(TAG, "Failed to start record.", e); } return EmptyArray.BYTE; } } + void invokeOneTouchRecordResult(int result) { + synchronized (mLock) { + if (mRecordListener != null) { + try { + mRecordListener.onOneTouchRecordResult(result); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); + } + } + } + } + + void invokeTimerRecordingResult(int result) { + synchronized (mLock) { + if (mRecordListener != null) { + try { + mRecordListener.onTimerRecordingResult(result); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); + } + } + } + } + private void invokeCallback(IHdmiControlCallback callback, int result) { try { callback.onComplete(result); @@ -1304,6 +1331,10 @@ public final class HdmiControlService extends SystemService { return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_TV); } + boolean isTvDevice() { + return tv() != null; + } + private HdmiCecLocalDevicePlayback playback() { return (HdmiCecLocalDevicePlayback) mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_PLAYBACK); diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java index 7d7a95bda706..907015b801a7 100644 --- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java +++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java @@ -18,6 +18,7 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCecDeviceInfo; import android.util.Slog; +import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; import java.io.UnsupportedEncodingException; /** @@ -153,6 +154,7 @@ final class NewDeviceAction extends FeatureAction { } tv().addCecDevice(new HdmiCecDeviceInfo( mDeviceLogicalAddress, mDevicePhysicalAddress, + tv().getPortId(mDevicePhysicalAddress), HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress), mVendorId, mDisplayName)); @@ -189,7 +191,8 @@ final class NewDeviceAction extends FeatureAction { } } - boolean isActionOf(int address, int path) { - return (mDeviceLogicalAddress == address) && (mDevicePhysicalAddress == path); + boolean isActionOf(ActiveSource activeSource) { + return (mDeviceLogicalAddress == activeSource.logicalAddress) + && (mDevicePhysicalAddress == activeSource.physicalAddress); } } diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java index 9ecbc5ebb338..befc640835a5 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java @@ -16,26 +16,24 @@ package com.android.server.hdmi; -import static android.hardware.hdmi.HdmiControlManager.MESSAGE_NO_RECORDING_CHECK_RECORDER_CONNECTION; -import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_ANALOGUE_SERVICE; -import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_CURRENTLY_SELECTED_SOURCE; -import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_DIGITAL_SERVICE; -import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_EXTERNAL_INPUT; -import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_STATUS_MESSAGE_START; +import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION; +import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE; +import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE; +import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE; +import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT; import android.util.Slog; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; /** - * Feature action that performs one touch record. This class only provides a skeleton of one touch - * play and has no detail implementation. + * Feature action that performs one touch record. */ public class OneTouchRecordAction extends FeatureAction { private static final String TAG = "OneTouchRecordAction"; - // Timer out for waiting <Record Status> - private static final int RECORD_STATUS_TIMEOUT = 120000; + // Timer out for waiting <Record Status> 120s + private static final int RECORD_STATUS_TIMEOUT_MS = 120000; // State that waits for <Record Status> once sending <Record On> private static final int STATE_WAITING_FOR_RECORD_STATUS = 1; @@ -65,13 +63,14 @@ public class OneTouchRecordAction extends FeatureAction { public void onSendCompleted(int error) { // if failed to send <Record On>, display error message and finish action. if (error != Constants.SEND_RESULT_SUCCESS) { - tv().displayOsd(MESSAGE_NO_RECORDING_CHECK_RECORDER_CONNECTION); + tv().announceOneTouchRecordResult( + ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); finish(); return; } mState = STATE_WAITING_FOR_RECORD_STATUS; - addTimer(mState, RECORD_STATUS_TIMEOUT); + addTimer(mState, RECORD_STATUS_TIMEOUT_MS); } }); } @@ -97,18 +96,16 @@ public class OneTouchRecordAction extends FeatureAction { } int recordStatus = cmd.getParams()[0]; + tv().announceOneTouchRecordResult(recordStatus); Slog.i(TAG, "Got record status:" + recordStatus + " from " + cmd.getSource()); - int recordStatusMessageCode = recordStatus + MESSAGE_RECORDING_STATUS_MESSAGE_START; - tv().displayOsd(recordStatusMessageCode); - // If recording started successfully, change state and keep this action until <Record Off> // received. Otherwise, finish action. - switch (recordStatusMessageCode) { - case MESSAGE_RECORDING_CURRENTLY_SELECTED_SOURCE: - case MESSAGE_RECORDING_DIGITAL_SERVICE: - case MESSAGE_RECORDING_ANALOGUE_SERVICE: - case MESSAGE_RECORDING_EXTERNAL_INPUT: + switch (recordStatus) { + case ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE: + case ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE: + case ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE: + case ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT: mState = STATE_RECORDING_IN_PROGRESS; mActionTimer.clearTimerMessage(); break; @@ -126,7 +123,7 @@ public class OneTouchRecordAction extends FeatureAction { return; } - tv().displayOsd(MESSAGE_NO_RECORDING_CHECK_RECORDER_CONNECTION); + tv().announceOneTouchRecordResult(ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); finish(); } diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java index 8296f695c1fc..f05394fb840f 100644 --- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java +++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java @@ -60,6 +60,12 @@ final class RoutingControlAction extends FeatureAction { // true if <Give Power Status> should be sent once the new active routing path is determined. private final boolean mQueryDevicePowerStatus; + // If set to true, call {@link HdmiControlService#invokeInputChangeListener()} when + // the routing control/active source change happens. The listener should be called if + // the events are triggered by external events such as manual switch port change or incoming + // <Inactive Source> command. + private final boolean mNotifyInputChange; + @Nullable private final IHdmiControlCallback mCallback; // The latest routing path. Updated by each <Routing Information> from CEC switches. @@ -71,6 +77,11 @@ final class RoutingControlAction extends FeatureAction { mCallback = callback; mCurrentRoutingPath = path; mQueryDevicePowerStatus = queryDevicePowerStatus; + // Callback is non-null when routing control action is brought up by binder API. Use + // this as an indicator for the input change notification. These API calls will get + // the result through this callback, not through notification. Any other events that + // trigger the routing control is external, for which notifcation is used. + mNotifyInputChange = (callback == null); } @Override @@ -111,7 +122,7 @@ final class RoutingControlAction extends FeatureAction { if (isPowerOnOrTransient(devicePowerStatus)) { sendSetStreamPath(); } else { - tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath)); + tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange); } } finishWithCallback(HdmiControlManager.RESULT_SUCCESS); @@ -155,13 +166,13 @@ final class RoutingControlAction extends FeatureAction { } }); } else { - tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath)); + tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange); finishWithCallback(HdmiControlManager.RESULT_SUCCESS); } return; case STATE_WAIT_FOR_REPORT_POWER_STATUS: if (isPowerOnOrTransient(getTvPowerStatus())) { - tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath)); + tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange); sendSetStreamPath(); } finishWithCallback(HdmiControlManager.RESULT_SUCCESS); @@ -179,7 +190,7 @@ final class RoutingControlAction extends FeatureAction { mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS); } else { - tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath)); + tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange); sendSetStreamPath(); finishWithCallback(HdmiControlManager.RESULT_SUCCESS); } diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java new file mode 100644 index 000000000000..1dc26f175ee6 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java @@ -0,0 +1,169 @@ +/* + * 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.hdmi; + +import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE; +import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL; +import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL; +import static android.hardware.hdmi.HdmiControlManager.TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION; + +import android.util.Slog; + +import com.android.server.hdmi.HdmiControlService.SendMessageCallback; + +import java.util.Arrays; + +/** + * Feature action that performs timer recording. + */ +public class TimerRecordingAction extends FeatureAction { + private static final String TAG = "TimerRecordingAction"; + + // Timer out for waiting <Timer Status> 120s. + private static final int TIMER_STATUS_TIMEOUT_MS = 120000; + + // State that waits for <Timer Status> once sending <Set XXX Timer> + private static final int STATE_WAITING_FOR_TIMER_STATUS = 1; + + private final int mRecorderAddress; + private final int mSourceType; + private final byte[] mRecordSource; + + TimerRecordingAction(HdmiCecLocalDevice source, int recorderAddress, int sourceType, + byte[] recordSource) { + super(source); + mRecorderAddress = recorderAddress; + mSourceType = sourceType; + mRecordSource = recordSource; + } + + @Override + boolean start() { + sendTimerMessage(); + return true; + } + + private void sendTimerMessage() { + HdmiCecMessage message = null; + switch (mSourceType) { + case TIMER_RECORDING_TYPE_DIGITAL: + message = HdmiCecMessageBuilder.buildSetDigitalTimer(getSourceAddress(), + mRecorderAddress, mRecordSource); + break; + case TIMER_RECORDING_TYPE_ANALOGUE: + message = HdmiCecMessageBuilder.buildSetAnalogueTimer(getSourceAddress(), + mRecorderAddress, mRecordSource); + break; + case TIMER_RECORDING_TYPE_EXTERNAL: + message = HdmiCecMessageBuilder.buildSetExternalTimer(getSourceAddress(), + mRecorderAddress, mRecordSource); + break; + default: + tv().announceTimerRecordingResult( + TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION); + finish(); + return; + } + sendCommand(message, new SendMessageCallback() { + @Override + public void onSendCompleted(int error) { + if (error != Constants.SEND_RESULT_SUCCESS) { + mState = STATE_WAITING_FOR_TIMER_STATUS; + addTimer(mState, TIMER_STATUS_TIMEOUT_MS); + finish(); + return; + } + } + }); + } + + @Override + boolean processCommand(HdmiCecMessage cmd) { + if (mState != STATE_WAITING_FOR_TIMER_STATUS) { + return false; + } + + if (cmd.getSource() != mRecorderAddress) { + return false; + } + + switch (cmd.getOpcode()) { + case Constants.MESSAGE_TIMER_STATUS: + return handleTimerStatus(cmd); + case Constants.MESSAGE_FEATURE_ABORT: + return handleFeatureAbort(cmd); + } + return false; + } + + private boolean handleTimerStatus(HdmiCecMessage cmd) { + byte[] timerStatusData = cmd.getParams(); + // [Timer Status Data] should be one or three bytes. + if (timerStatusData.length == 1 || timerStatusData.length == 3) { + tv().announceTimerRecordingResult(bytesToInt(timerStatusData)); + Slog.i(TAG, "Received [Timer Status Data]:" + Arrays.toString(timerStatusData)); + } else { + Slog.w(TAG, "Invalid [Timer Status Data]:" + Arrays.toString(timerStatusData)); + } + + // Unlike one touch record, finish timer record when <Timer Status> is received. + finish(); + return true; + } + + private boolean handleFeatureAbort(HdmiCecMessage cmd) { + byte[] params = cmd.getParams(); + int messageType = params[0]; + switch (messageType) { + case Constants.MESSAGE_SET_DIGITAL_TIMER: // fall through + case Constants.MESSAGE_SET_ANALOG_TIMER: // fall through + case Constants.MESSAGE_SET_EXTERNAL_TIMER: // fall through + break; + default: + return false; + } + int reason = params[1]; + Slog.i(TAG, "[Feature Abort] for " + messageType + " reason:" + reason); + tv().announceTimerRecordingResult(TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION); + finish(); + return true; + } + + // Convert byte array to int. + private static int bytesToInt(byte[] data) { + if (data.length > 4) { + throw new IllegalArgumentException("Invalid data size:" + Arrays.toString(data)); + } + int result = 0; + for (int i = 0; i < data.length; ++i) { + int shift = (3 - i) * 8; + result |= ((data[i] & 0xFF) << shift); + } + return result; + } + + @Override + void handleTimerEvent(int state) { + if (mState != state) { + Slog.w(TAG, "Timeout in invalid state:[Expected:" + mState + ", Actual:" + state + "]"); + return; + } + + tv().announceTimerRecordingResult(TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION); + finish(); + } +} diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java index eaf548064d45..ee4583310a5f 100644 --- a/services/core/java/com/android/server/job/JobServiceContext.java +++ b/services/core/java/com/android/server/job/JobServiceContext.java @@ -285,7 +285,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne case MSG_CALLBACK: if (DEBUG) { Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob + " v:" + - VERB_STRINGS[mVerb]); + (mVerb >= 0 ? VERB_STRINGS[mVerb] : "[invalid]")); } removeMessages(MSG_TIMEOUT); @@ -518,7 +518,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS; if (DEBUG) { Slog.d(TAG, "Scheduling time out for '" + - mRunningJob.getServiceComponent().getShortClassName() + "' tId: " + + mRunningJob.getServiceComponent().getShortClassName() + "' jId: " + mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s"); } Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT); diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java index 07ffe4d885b3..2213934bbae9 100644 --- a/services/core/java/com/android/server/job/controllers/IdleController.java +++ b/services/core/java/com/android/server/job/controllers/IdleController.java @@ -137,6 +137,9 @@ public class IdleController extends StateController { filter.addAction(Intent.ACTION_DREAMING_STARTED); filter.addAction(Intent.ACTION_DREAMING_STOPPED); + // Debugging/instrumentation + filter.addAction(ACTION_TRIGGER_IDLE); + mContext.registerReceiver(this, filter); } @@ -181,6 +184,16 @@ public class IdleController extends StateController { @Override public void dumpControllerState(PrintWriter pw) { - + synchronized (mTrackedTasks) { + pw.print("Idle: "); + pw.println(mIdleTracker.isIdle() ? "true" : "false"); + pw.println(mTrackedTasks.size()); + for (int i = 0; i < mTrackedTasks.size(); i++) { + final JobStatus js = mTrackedTasks.get(i); + pw.print(" "); + pw.print(String.valueOf(js.hashCode()).substring(0, 3)); + pw.println(".."); + } + } } } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index e9df507540a6..2f1bd60fe36b 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -16,6 +16,7 @@ package com.android.server.media; +import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -33,14 +34,9 @@ import android.media.session.ISessionController; import android.media.session.ISessionControllerCallback; import android.media.session.MediaController; import android.media.session.MediaSession; -import android.media.session.MediaSessionInfo; import android.media.session.ParcelableVolumeInfo; import android.media.session.PlaybackState; import android.media.AudioAttributes; -import android.media.AudioManager; -import android.media.MediaMetadata; -import android.media.Rating; -import android.media.VolumeProvider; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -85,7 +81,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private final int mOwnerPid; private final int mOwnerUid; private final int mUserId; - private final MediaSessionInfo mSessionInfo; + private final String mPackageName; private final String mTag; private final ControllerStub mController; private final SessionStub mSession; @@ -98,7 +94,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private long mFlags; private IMediaRouter mMediaRouter; - private ComponentName mMediaButtonReceiver; + private PendingIntent mMediaButtonReceiver; + private PendingIntent mLaunchIntent; // TransportPerformer fields @@ -129,8 +126,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mOwnerPid = ownerPid; mOwnerUid = ownerUid; mUserId = userId; - mSessionInfo = new MediaSessionInfo(UUID.randomUUID().toString(), ownerPackageName, - ownerPid); + mPackageName = ownerPackageName; mTag = tag; mController = new ControllerStub(); mSession = new SessionStub(); @@ -164,11 +160,25 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { * * @return Info that identifies this session. */ - public MediaSessionInfo getSessionInfo() { - return mSessionInfo; + public String getPackageName() { + return mPackageName; + } + + /** + * Get the tag for the session. + * + * @return The session's tag. + */ + public String getTag() { + return mTag; } - public ComponentName getMediaButtonReceiver() { + /** + * Get the intent the app set for their media button receiver. + * + * @return The pending intent set by the app or null. + */ + public PendingIntent getMediaButtonReceiver() { return mMediaButtonReceiver; } @@ -402,9 +412,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { pw.println(prefix + mTag + " " + this); final String indent = prefix + " "; + // We print the hashcode for matching with the list in user records pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid + ", userId=" + mUserId); - pw.println(indent + "info=" + mSessionInfo.toString()); + pw.println(indent + "package=" + mPackageName); pw.println(indent + "active=" + mIsActive); pw.println(indent + "flags=" + mFlags); pw.println(indent + "rating type=" + mRatingType); @@ -413,6 +424,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { pw.println(indent + "metadata:" + getShortMetadataString()); } + @Override + public String toString() { + return mPackageName + "/" + mTag; + } + private String getShortMetadataString() { int fields = mMetadata == null ? 0 : mMetadata.size(); String title = mMetadata == null ? null : mMetadata @@ -646,8 +662,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setMediaButtonReceiver(ComponentName mbr) { - mMediaButtonReceiver = mbr; + public void setMediaButtonReceiver(PendingIntent pi) { + mMediaButtonReceiver = pi; + } + + @Override + public void setLaunchPendingIntent(PendingIntent pi) { + mLaunchIntent = pi; } @Override @@ -916,8 +937,18 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public MediaSessionInfo getSessionInfo() { - return mSessionInfo; + public String getPackageName() { + return mPackageName; + } + + @Override + public String getTag() { + return mTag; + } + + @Override + public PendingIntent getLaunchPendingIntent() { + return mLaunchIntent; } @Override diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index b0ccd622715a..92644ce85c2a 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -20,6 +20,8 @@ import android.Manifest; import android.app.Activity; import android.app.ActivityManager; import android.app.KeyguardManager; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -407,16 +409,6 @@ public class MediaSessionService extends SystemService implements Monitor { return user; } - private int findIndexOfSessionForIdLocked(String sessionId) { - for (int i = mAllSessions.size() - 1; i >= 0; i--) { - MediaSessionRecord session = mAllSessions.get(i); - if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) { - return i; - } - } - return -1; - } - private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) { for (int i = mSessionsListeners.size() - 1; i >= 0; i--) { if (mSessionsListeners.get(i).mListener == listener) { @@ -436,7 +428,7 @@ public class MediaSessionService extends SystemService implements Monitor { List<MediaSessionRecord> records = mPriorityStack.getActiveSessions(userId); int size = records.size(); if (size > 0) { - persistMediaButtonReceiverLocked(records.get(0)); + rememberMediaButtonReceiverLocked(records.get(0)); } ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>(); for (int i = 0; i < size; i++) { @@ -469,13 +461,11 @@ public class MediaSessionService extends SystemService implements Monitor { } } - private void persistMediaButtonReceiverLocked(MediaSessionRecord record) { - ComponentName receiver = record.getMediaButtonReceiver(); - if (receiver != null) { - Settings.System.putStringForUser(mContentResolver, - Settings.System.MEDIA_BUTTON_RECEIVER, - receiver == null ? "" : receiver.flattenToString(), - UserHandle.USER_CURRENT); + private void rememberMediaButtonReceiverLocked(MediaSessionRecord record) { + PendingIntent receiver = record.getMediaButtonReceiver(); + UserRecord user = mUserRecords.get(record.getUserId()); + if (receiver != null && user != null) { + user.mLastMediaButtonReceiver = receiver; } } @@ -486,6 +476,7 @@ public class MediaSessionService extends SystemService implements Monitor { final class UserRecord { private final int mUserId; private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>(); + private PendingIntent mLastMediaButtonReceiver; public UserRecord(Context context, int userId) { mUserId = userId; @@ -521,12 +512,13 @@ public class MediaSessionService extends SystemService implements Monitor { public void dumpLocked(PrintWriter pw, String prefix) { pw.println(prefix + "Record for user " + mUserId); String indent = prefix + " "; + pw.println(indent + "MediaButtonReceiver:" + mLastMediaButtonReceiver); int size = mSessions.size(); pw.println(indent + size + " Sessions:"); for (int i = 0; i < size; i++) { - // Just print the session info, the full session dump will + // Just print the short version, the full session dump will // already be in the list of all sessions. - pw.println(indent + mSessions.get(i).getSessionInfo()); + pw.println(indent + mSessions.get(i).toString()); } } } @@ -767,9 +759,9 @@ public class MediaSessionService extends SystemService implements Monitor { private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags, MediaSessionRecord session) { if (DEBUG) { - String sessionInfo = session == null ? null : session.getSessionInfo().toString(); - Log.d(TAG, "Adjusting session " + sessionInfo + " by " + direction + ". flags=" + flags - + ", suggestedStream=" + suggestedStream); + String description = session == null ? null : session.toString(); + Log.d(TAG, "Adjusting session " + description + " by " + direction + ". flags=" + + flags + ", suggestedStream=" + suggestedStream); } if (session == null) { @@ -832,7 +824,7 @@ public class MediaSessionService extends SystemService implements Monitor { MediaSessionRecord session) { if (session != null) { if (DEBUG) { - Log.d(TAG, "Sending media key to " + session.getSessionInfo()); + Log.d(TAG, "Sending media key to " + session.toString()); } if (needWakeLock) { mKeyEventReceiver.aquireWakeLockLocked(); @@ -843,21 +835,43 @@ public class MediaSessionService extends SystemService implements Monitor { needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, mKeyEventReceiver); } else { - if (needWakeLock) { - mMediaEventWakeLock.acquire(); - } - if (DEBUG) { - Log.d(TAG, "Sending media key ordered broadcast"); - } - // Fallback to legacy behavior - Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - if (needWakeLock) { - keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, - WAKELOCK_RELEASE_ON_FINISHED); + // Launch the last PendingIntent we had with priority + int userId = ActivityManager.getCurrentUser(); + UserRecord user = mUserRecords.get(userId); + if (user.mLastMediaButtonReceiver != null) { + if (DEBUG) { + Log.d(TAG, "Sending media key to last known PendingIntent"); + } + if (needWakeLock) { + mKeyEventReceiver.aquireWakeLockLocked(); + } + Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + try { + user.mLastMediaButtonReceiver.send(getContext(), + needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, + mediaButtonIntent, mKeyEventReceiver, null); + } catch (CanceledException e) { + Log.i(TAG, "Error sending key event to media button receiver " + + user.mLastMediaButtonReceiver, e); + } + } else { + if (DEBUG) { + Log.d(TAG, "Sending media key ordered broadcast"); + } + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + } + // Fallback to legacy behavior + Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + if (needWakeLock) { + keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, + WAKELOCK_RELEASE_ON_FINISHED); + } + getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, + null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null); } - getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, - null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null); } } @@ -904,7 +918,8 @@ public class MediaSessionService extends SystemService implements Monitor { private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler); - class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable { + class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable, + PendingIntent.OnFinished { private final Handler mHandler; private int mRefCount = 0; private int mLastTimeoutId = 0; @@ -963,6 +978,12 @@ public class MediaSessionService extends SystemService implements Monitor { mMediaEventWakeLock.release(); mHandler.removeCallbacks(this); } + + @Override + public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, + String resultData, Bundle resultExtras) { + onReceiveResult(resultCode, null); + } }; BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index a6711c3023e6..f117f9966b57 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -740,6 +740,13 @@ public class NotificationManagerService extends SystemService { private SettingsObserver mSettingsObserver; private ZenModeHelper mZenModeHelper; + private final Runnable mBuzzBeepBlinked = new Runnable() { + @Override + public void run() { + mStatusBar.buzzBeepBlinked(); + } + }; + static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { int[] ar = r.getIntArray(resid); if (ar == null) { @@ -1645,6 +1652,7 @@ public class NotificationManagerService extends SystemService { } private void buzzBeepBlinkLocked(NotificationRecord record) { + boolean buzzBeepBlinked = false; final Notification notification = record.sbn.getNotification(); // Should this notification make noise, vibe, or use the LED? @@ -1726,6 +1734,7 @@ public class NotificationManagerService extends SystemService { + " on stream " + audioStreamType); player.playAsync(soundUri, record.sbn.getUser(), looping, audioStreamType); + buzzBeepBlinked = true; } } catch (RemoteException e) { } finally { @@ -1765,6 +1774,7 @@ public class NotificationManagerService extends SystemService { : mFallbackVibrationPattern, ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1, audioAttributesForNotification(notification)); + buzzBeepBlinked = true; } finally { Binder.restoreCallingIdentity(identity); } @@ -1775,6 +1785,7 @@ public class NotificationManagerService extends SystemService { notification.vibrate, ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1, audioAttributesForNotification(notification)); + buzzBeepBlinked = true; } } } @@ -1791,9 +1802,13 @@ public class NotificationManagerService extends SystemService { if (mUseAttentionLight) { mAttentionLight.pulse(); } + buzzBeepBlinked = true; } else if (wasShowLights) { updateLightsLocked(); } + if (buzzBeepBlinked) { + mHandler.post(mBuzzBeepBlinked); + } } private static AudioAttributes audioAttributesForNotification(Notification n) { diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java index 81f64b1081f1..3069ad96797b 100644 --- a/services/core/java/com/android/server/notification/ZenLog.java +++ b/services/core/java/com/android/server/notification/ZenLog.java @@ -30,6 +30,8 @@ import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; +import java.util.HashSet; +import java.util.Set; public class ZenLog { private static final String TAG = "ZenLog"; @@ -41,6 +43,10 @@ public class ZenLog { private static final String[] MSGS = new String[SIZE]; private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); + private static final Set<String> SYSTEM_PACKAGES = new HashSet<String>(Arrays.asList( + "android", + "com.android.systemui" + )); private static final int TYPE_INTERCEPTED = 1; private static final int TYPE_ALLOW_DISABLE = 2; @@ -61,6 +67,7 @@ public class ZenLog { } public static void traceAllowDisable(String pkg, boolean allowDisable, String reason) { + if (SYSTEM_PACKAGES.contains(pkg)) return; append(TYPE_ALLOW_DISABLE, allowDisable + "," + pkg + "," + reason); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index a896550e6e4f..1289cf78c9f2 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -37,7 +37,9 @@ import android.media.AudioManager; import android.net.Uri; import android.os.Handler; import android.os.IBinder; +import android.os.UserHandle; import android.provider.Settings.Global; +import android.provider.Settings.Secure; import android.service.notification.ZenModeConfig; import android.telecomm.TelecommManager; import android.util.Slog; @@ -53,11 +55,9 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.Calendar; import java.util.Date; -import java.util.HashSet; -import java.util.Set; +import java.util.Objects; /** * NotificationManagerService helper for functionality related to zen mode. @@ -84,17 +84,6 @@ public class ZenModeHelper { private AudioManager mAudioManager; private int mPreviousRingerMode = -1; - // temporary, until we update apps to provide metadata - private static final Set<String> MESSAGE_PACKAGES = new HashSet<String>(Arrays.asList( - "com.google.android.talk", - "com.android.mms", - "com.android.example.notificationshowcase" - )); - private static final Set<String> SYSTEM_PACKAGES = new HashSet<String>(Arrays.asList( - "android", - "com.android.systemui" - )); - public ZenModeHelper(Context context, Handler handler) { mContext = context; mHandler = handler; @@ -249,9 +238,7 @@ public class ZenModeHelper { allowDisable = mZenMode == Global.ZEN_MODE_OFF || mConfig.allowCalls; reason = mZenMode == Global.ZEN_MODE_OFF ? "zenOff" : "allowCalls"; } - if (!SYSTEM_PACKAGES.contains(pkg)) { - ZenLog.traceAllowDisable(pkg, allowDisable, reason); - } + ZenLog.traceAllowDisable(pkg, allowDisable, reason); return allowDisable; } @@ -305,8 +292,7 @@ public class ZenModeHelper { } private boolean isSystem(NotificationRecord record) { - return SYSTEM_PACKAGES.contains(record.sbn.getPackageName()) - && record.isCategory(Notification.CATEGORY_SYSTEM); + return record.isCategory(Notification.CATEGORY_SYSTEM); } private boolean isAlarm(NotificationRecord record) { @@ -330,8 +316,16 @@ public class ZenModeHelper { && pkg.equals(mDefaultPhoneApp.getPackageName()); } + private boolean isDefaultMessagingApp(NotificationRecord record) { + final int userId = record.getUserId(); + if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false; + final String defaultApp = Secure.getStringForUser(mContext.getContentResolver(), + Secure.SMS_DEFAULT_APPLICATION, userId); + return Objects.equals(defaultApp, record.sbn.getPackageName()); + } + private boolean isMessage(NotificationRecord record) { - return MESSAGE_PACKAGES.contains(record.sbn.getPackageName()); + return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record); } private boolean audienceMatches(NotificationRecord record) { diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java index 3ce19c1fe43a..c61d344f48e6 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java @@ -33,17 +33,24 @@ import android.os.UserHandle; class CrossProfileIntentFilter extends IntentFilter { private static final String ATTR_TARGET_USER_ID = "targetUserId"; private static final String ATTR_FLAGS = "flags"; + private static final String ATTR_OWNER_USER_ID = "ownerUserId"; + private static final String ATTR_OWNER_PACKAGE = "ownerPackage"; private static final String ATTR_FILTER = "filter"; private static final String TAG = "CrossProfileIntentFilter"; // If the intent matches the IntentFilter, then it can be forwarded to this userId. final int mTargetUserId; + final int mOwnerUserId; // userId of the app which has set this CrossProfileIntentFilter. + final String mOwnerPackage; // packageName of the app. final int mFlags; - CrossProfileIntentFilter(IntentFilter filter, int targetUserId, int flags) { + CrossProfileIntentFilter(IntentFilter filter, String ownerPackage, int ownerUserId, + int targetUserId, int flags) { super(filter); mTargetUserId = targetUserId; + mOwnerUserId = ownerUserId; + mOwnerPackage = ownerPackage; mFlags = flags; } @@ -55,25 +62,20 @@ class CrossProfileIntentFilter extends IntentFilter { return mFlags; } + public int getOwnerUserId() { + return mOwnerUserId; + } + + public String getOwnerPackage() { + return mOwnerPackage; + } + CrossProfileIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException { - String targetUserIdString = parser.getAttributeValue(null, ATTR_TARGET_USER_ID); - if (targetUserIdString == null) { - String msg = "Missing element under " + TAG +": " + ATTR_TARGET_USER_ID + " at " + - parser.getPositionDescription(); - PackageManagerService.reportSettingsProblem(Log.WARN, msg); - mTargetUserId = UserHandle.USER_NULL; - } else { - mTargetUserId = Integer.parseInt(targetUserIdString); - } - String flagsString = parser.getAttributeValue(null, ATTR_FLAGS); - if (flagsString == null) { - String msg = "Missing element under " + TAG +": " + ATTR_FLAGS + " at " + - parser.getPositionDescription(); - PackageManagerService.reportSettingsProblem(Log.WARN, msg); - mFlags = 0; - } else { - mFlags = Integer.parseInt(flagsString); - } + mTargetUserId = getIntFromXml(parser, ATTR_TARGET_USER_ID, UserHandle.USER_NULL); + mOwnerUserId = getIntFromXml(parser, ATTR_OWNER_USER_ID, UserHandle.USER_NULL); + mOwnerPackage = getStringFromXml(parser, ATTR_OWNER_PACKAGE, ""); + mFlags = getIntFromXml(parser, ATTR_FLAGS, 0); + int outerDepth = parser.getDepth(); String tagName = parser.getName(); int type; @@ -103,9 +105,31 @@ class CrossProfileIntentFilter extends IntentFilter { } } + String getStringFromXml(XmlPullParser parser, String attribute, String defaultValue) { + String value = parser.getAttributeValue(null, attribute); + if (value == null) { + String msg = "Missing element under " + TAG +": " + attribute + " at " + + parser.getPositionDescription(); + PackageManagerService.reportSettingsProblem(Log.WARN, msg); + return defaultValue; + } else { + return value; + } + } + + int getIntFromXml(XmlPullParser parser, String attribute, int defaultValue) { + String stringValue = getStringFromXml(parser, attribute, null); + if (stringValue != null) { + return Integer.parseInt(stringValue); + } + return defaultValue; + } + public void writeToXml(XmlSerializer serializer) throws IOException { serializer.attribute(null, ATTR_TARGET_USER_ID, Integer.toString(mTargetUserId)); serializer.attribute(null, ATTR_FLAGS, Integer.toString(mFlags)); + serializer.attribute(null, ATTR_OWNER_USER_ID, Integer.toString(mOwnerUserId)); + serializer.attribute(null, ATTR_OWNER_PACKAGE, mOwnerPackage); serializer.startTag(null, ATTR_FILTER); super.writeToXml(serializer); serializer.endTag(null, ATTR_FILTER); diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 09cf3922acec..b7b1c233e77d 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -29,6 +29,7 @@ import android.content.pm.PackageInfo; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.graphics.Rect; +import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.IInterface; @@ -36,6 +37,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.util.Log; import android.util.Slog; @@ -307,6 +309,30 @@ public class LauncherAppsService extends SystemService { } } + @Override + public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds, + Bundle opts, UserHandle user) throws RemoteException { + ensureInUserProfiles(user, "Cannot show app details for unrelated profile " + user); + if (!isUserEnabled(user)) { + throw new IllegalStateException("Cannot show app details for disabled profile " + + user); + } + + long ident = Binder.clearCallingIdentity(); + try { + String packageName = component.getPackageName(); + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", packageName, null)); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | + Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + intent.setSourceBounds(sourceBounds); + mContext.startActivityAsUser(intent, opts, user); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private class MyPackageMonitor extends PackageMonitor { /** Checks if user is a profile of or same as listeningUser. diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index db915e2a2a7f..6036bcfd2d90 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -24,10 +24,11 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstaller; -import android.content.pm.IPackageInstallerObserver; +import android.content.pm.IPackageInstallerCallback; import android.content.pm.IPackageInstallerSession; import android.content.pm.InstallSessionInfo; import android.content.pm.InstallSessionParams; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.FileUtils; import android.os.HandlerThread; @@ -54,6 +55,7 @@ import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class PackageInstallerService extends IPackageInstaller.Stub { private static final String TAG = "PackageInstaller"; @@ -80,7 +82,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { @GuardedBy("mSessions") private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>(); - private RemoteCallbackList<IPackageInstallerObserver> mObservers = new RemoteCallbackList<>(); + private RemoteCallbackList<IPackageInstallerCallback> mCallbacks = new RemoteCallbackList<>(); private static final FilenameFilter sStageFilter = new FilenameFilter() { @Override @@ -152,8 +154,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public int createSession(String installerPackageName, InstallSessionParams params, - int userId) { + public int createSession(InstallSessionParams params, String installerPackageName, int userId) { final int callingUid = Binder.getCallingUid(); mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession"); @@ -172,14 +173,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub { params.installFlags |= INSTALL_REPLACE_EXISTING; } - if (params.mode == InstallSessionParams.MODE_INVALID) { - throw new IllegalArgumentException("Params must have valid mode set"); + switch (params.mode) { + case InstallSessionParams.MODE_FULL_INSTALL: + case InstallSessionParams.MODE_INHERIT_EXISTING: + break; + default: + throw new IllegalArgumentException("Params must have valid mode set"); } // Sanity check that install could fit - if (params.deltaSize > 0) { + if (params.sizeBytes > 0) { try { - mPm.freeStorage(params.deltaSize); + mPm.freeStorage(params.sizeBytes); } catch (IOException e) { throw ExceptionUtils.wrap(e); } @@ -248,8 +253,22 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public List<InstallSessionInfo> getSessions(int userId) { - mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getSessions"); + public InstallSessionInfo getSessionInfo(int sessionId) { + synchronized (mSessions) { + final PackageInstallerSession session = mSessions.get(sessionId); + final boolean isOwner = (session != null) + && (session.installerUid == Binder.getCallingUid()); + if (!isOwner) { + enforceCallerCanReadSessions(); + } + return session != null ? session.generateInfo() : null; + } + } + + @Override + public List<InstallSessionInfo> getAllSessions(int userId) { + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions"); + enforceCallerCanReadSessions(); final List<InstallSessionInfo> result = new ArrayList<>(); synchronized (mSessions) { @@ -264,9 +283,29 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override + public List<InstallSessionInfo> getMySessions(String installerPackageName, int userId) { + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions"); + mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName); + + final List<InstallSessionInfo> result = new ArrayList<>(); + synchronized (mSessions) { + for (int i = 0; i < mSessions.size(); i++) { + final PackageInstallerSession session = mSessions.valueAt(i); + if (Objects.equals(session.installerPackageName, installerPackageName) + && session.userId == userId) { + result.add(session.generateInfo()); + } + } + } + return result; + } + + @Override public void uninstall(String packageName, int flags, IPackageDeleteObserver observer, int userId) { mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall"); + + // TODO: enforce installer of record or permission mPm.deletePackageAsUser(packageName, observer, userId, flags); } @@ -280,17 +319,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public void registerObserver(IPackageInstallerObserver observer, int userId) { - mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerObserver"); + public void registerCallback(IPackageInstallerCallback callback, int userId) { + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerCallback"); + enforceCallerCanReadSessions(); - // TODO: consider restricting to active launcher app only - mObservers.register(observer, new UserHandle(userId)); + mCallbacks.register(callback, new UserHandle(userId)); } @Override - public void unregisterObserver(IPackageInstallerObserver observer, int userId) { - mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "unregisterObserver"); - mObservers.unregister(observer); + public void unregisterCallback(IPackageInstallerCallback callback) { + mCallbacks.unregister(callback); } private int getSessionUserId(int sessionId) { @@ -299,52 +337,68 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } + /** + * We allow those with permission, or the current home app. + */ + private void enforceCallerCanReadSessions() { + final boolean hasPermission = (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.READ_INSTALL_SESSIONS) + == PackageManager.PERMISSION_GRANTED); + final boolean isHomeApp = mPm.checkCallerIsHomeApp(); + if (hasPermission || isHomeApp) { + return; + } else { + throw new SecurityException("Caller must be current home app to read install sessions"); + } + } + private void notifySessionCreated(InstallSessionInfo info) { final int userId = getSessionUserId(info.sessionId); - final int n = mObservers.beginBroadcast(); + final int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { - final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i); - final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i); + final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); + final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); + // TODO: dispatch notifications for slave profiles if (userId == user.getIdentifier()) { try { - observer.onSessionCreated(info); + callback.onSessionCreated(info.sessionId); } catch (RemoteException ignored) { } } } - mObservers.finishBroadcast(); + mCallbacks.finishBroadcast(); } - private void notifySessionProgress(int sessionId, int progress) { + private void notifySessionProgressChanged(int sessionId, float progress) { final int userId = getSessionUserId(sessionId); - final int n = mObservers.beginBroadcast(); + final int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { - final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i); - final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i); + final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); + final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); if (userId == user.getIdentifier()) { try { - observer.onSessionProgress(sessionId, progress); + callback.onSessionProgressChanged(sessionId, progress); } catch (RemoteException ignored) { } } } - mObservers.finishBroadcast(); + mCallbacks.finishBroadcast(); } private void notifySessionFinished(int sessionId, boolean success) { final int userId = getSessionUserId(sessionId); - final int n = mObservers.beginBroadcast(); + final int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { - final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i); - final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i); + final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); + final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); if (userId == user.getIdentifier()) { try { - observer.onSessionFinished(sessionId, success); + callback.onSessionFinished(sessionId, success); } catch (RemoteException ignored) { } } } - mObservers.finishBroadcast(); + mCallbacks.finishBroadcast(); } void dump(IndentingPrintWriter pw) { @@ -374,8 +428,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } class Callback { - public void onSessionProgress(PackageInstallerSession session, int progress) { - notifySessionProgress(session.sessionId, progress); + public void onSessionProgressChanged(PackageInstallerSession session, float progress) { + notifySessionProgressChanged(session.sessionId, progress); } public void onSessionFinished(PackageInstallerSession session, boolean success) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 0e6a3f07e0fc..06e1d5359899 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -71,6 +71,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // TODO: enforce INSTALL_ALLOW_DOWNGRADE // TODO: handle INSTALL_EXTERNAL, INSTALL_INTERNAL + // TODO: treat INHERIT_EXISTING as installExistingPackage() + private final PackageInstallerService.Callback mCallback; private final PackageManagerService mPm; private final Handler mHandler; @@ -84,7 +86,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { public final long createdMillis; public final File sessionStageDir; - private static final int MSG_INSTALL = 0; + private static final int MSG_COMMIT = 0; private Handler.Callback mHandlerCallback = new Handler.Callback() { @Override @@ -95,7 +97,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } try { - installLocked(); + commitLocked(); } catch (PackageManagerException e) { Slog.e(TAG, "Install failed: " + e); destroyInternal(); @@ -114,8 +116,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final Object mLock = new Object(); - private int mClientProgress; - private int mProgress = 0; + private float mClientProgress; + private float mProgress = 0; private String mPackageName; private int mVersionCode; @@ -168,23 +170,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.progress = mProgress; info.mode = params.mode; - info.packageName = params.packageName; - info.icon = params.icon; - info.title = params.title; + info.sizeBytes = params.sizeBytes; + info.appPackageName = params.appPackageName; + info.appIcon = params.appIcon; + info.appLabel = params.appLabel; return info; } @Override - public void setClientProgress(int progress) { + public void setClientProgress(float progress) { mClientProgress = progress; - mProgress = MathUtils.constrain( - (int) (((float) mClientProgress) / ((float) params.progressMax)) * 80, 0, 80); - mCallback.onSessionProgress(this, mProgress); + mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f); + mCallback.onSessionProgressChanged(this, mProgress); } @Override - public void addClientProgress(int progress) { + public void addClientProgress(float progress) { setClientProgress(mClientProgress + progress); } @@ -250,12 +252,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override - public void install(IPackageInstallObserver2 observer) { + public void commit(IPackageInstallObserver2 observer) { Preconditions.checkNotNull(observer); - mHandler.obtainMessage(MSG_INSTALL, observer).sendToTarget(); + mHandler.obtainMessage(MSG_COMMIT, observer).sendToTarget(); } - private void installLocked() throws PackageManagerException { + private void commitLocked() throws PackageManagerException { if (mInvalid) { throw new PackageManagerException(INSTALL_FAILED_ALREADY_EXISTS, "Invalid session"); } @@ -295,7 +297,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } // TODO: surface more granular state from dexopt - mCallback.onSessionProgress(this, 90); + mCallback.onSessionProgressChanged(this, 0.9f); // TODO: for ASEC based applications, grow and stream in packages @@ -458,7 +460,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override - public void destroy() { + public void close() { + // Currently ignored + } + + @Override + public void abandon() { try { destroyInternal(); } finally { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index b96f67299085..68ae6ff65c91 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -4728,6 +4728,28 @@ public class PackageManagerService extends IPackageManager.Stub { return allInstructionSets; } + @Override + public void forceDexOpt(String packageName) { + enforceSystemOrRoot("forceDexOpt"); + + PackageParser.Package pkg; + synchronized (mPackages) { + pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Missing package: " + packageName); + } + } + + synchronized (mInstallLock) { + final String[] instructionSets = new String[] { + getPrimaryInstructionSet(pkg.applicationInfo) }; + final int res = performDexOptLI(pkg, instructionSets, true, false, true); + if (res != DEX_OPT_PERFORMED) { + throw new IllegalStateException("Failed to dexopt: " + res); + } + } + } + private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets, boolean forceDex, boolean defer, boolean inclDependencies) { HashSet<String> done; @@ -4839,16 +4861,6 @@ public class PackageManagerService extends IPackageManager.Stub { private void updateSharedLibrariesLPw(PackageParser.Package pkg, PackageParser.Package changingLib) throws PackageManagerException { - // We might be upgrading from a version of the platform that did not - // provide per-package native library directories for system apps. - // Fix that up here. - if (isSystemApp(pkg)) { - PackageSetting ps = mSettings.mPackages.get(pkg.applicationInfo.packageName); - if (!isUpdatedSystemApp(pkg)) { - setBundledAppAbisAndRoots(pkg, ps); - } - } - if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) { final ArraySet<String> usesLibraryFiles = new ArraySet<>(); int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0; @@ -5236,6 +5248,7 @@ public class PackageManagerService extends IPackageManager.Stub { // The system package is special. dataPath = new File (Environment.getDataDirectory(), "system"); pkg.applicationInfo.dataDir = dataPath.getPath(); + } else { // This is a normal package, need to make its data directory. dataPath = getDataPathForPackage(pkg.packageName, 0); @@ -5370,6 +5383,26 @@ public class PackageManagerService extends IPackageManager.Stub { NativeLibraryHelper.removeNativeBinariesFromDirLI( new File(codePath, LIB_DIR_NAME), false /* delete dirs */); setBundledAppAbisAndRoots(pkg, pkgSetting); + + // If we haven't found any native libraries for the app, check if it has + // renderscript code. We'll need to force the app to 32 bit if it has + // renderscript bitcode. + if (pkg.applicationInfo.primaryCpuAbi == null + && pkg.applicationInfo.secondaryCpuAbi == null + && Build.SUPPORTED_64_BIT_ABIS.length > 0) { + NativeLibraryHelper.Handle handle = null; + try { + handle = NativeLibraryHelper.Handle.create(scanFile); + if (NativeLibraryHelper.hasRenderscriptBitcode(handle)) { + pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; + } + } catch (IOException ioe) { + Slog.w(TAG, "Error scanning system app : " + ioe); + } finally { + IoUtils.closeQuietly(handle); + } + } + setNativeLibraryPaths(pkg); } else { // TODO: We can probably be smarter about this stuff. For installed apps, @@ -5504,11 +5537,20 @@ public class PackageManagerService extends IPackageManager.Stub { } } } + } - pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi; - pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi; + // This is a special case for the "system" package, where the ABI is + // dictated by the zygote configuration (and init.rc). We should keep track + // of this ABI so that we can deal with "normal" applications that run under + // the same UID correctly. + if (mPlatformPackage == pkg) { + pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ? + Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]; } + pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi; + pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi; + Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.applicationInfo.packageName + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa=" + pkg.applicationInfo.nativeLibraryRootRequiresIsa); @@ -10785,7 +10827,6 @@ public class PackageManagerService extends IPackageManager.Stub { // writer synchronized (mPackages) { PackageSetting ps = mSettings.mPackages.get(newPkg.packageName); - setBundledAppAbisAndRoots(newPkg, ps); updatePermissionsLPw(newPkg.packageName, newPkg, UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG); if (applyUserRestrictions) { @@ -11594,22 +11635,25 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - public void addCrossProfileIntentFilter(IntentFilter intentFilter, int sourceUserId, - int targetUserId, int flags) { + public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage, + int ownerUserId, int sourceUserId, int targetUserId, int flags) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); + int callingUid = Binder.getCallingUid(); + enforceOwnerRights(ownerPackage, ownerUserId, callingUid); if (intentFilter.countActions() == 0) { Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions"); return; } synchronized (mPackages) { CrossProfileIntentFilter filter = new CrossProfileIntentFilter(intentFilter, - targetUserId, flags); + ownerPackage, UserHandle.getUserId(callingUid), targetUserId, flags); mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(filter); mSettings.writePackageRestrictionsLPr(sourceUserId); } } + @Override public void addCrossProfileIntentsForPackage(String packageName, int sourceUserId, int targetUserId) { mContext.enforceCallingOrSelfPermission( @@ -11627,16 +11671,21 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - public void clearCrossProfileIntentFilters(int sourceUserId) { + public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage, + int ownerUserId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); + int callingUid = Binder.getCallingUid(); + enforceOwnerRights(ownerPackage, ownerUserId, callingUid); + int callingUserId = UserHandle.getUserId(callingUid); synchronized (mPackages) { CrossProfileIntentResolver resolver = mSettings.editCrossProfileIntentResolverLPw(sourceUserId); HashSet<CrossProfileIntentFilter> set = new HashSet<CrossProfileIntentFilter>(resolver.filterSet()); for (CrossProfileIntentFilter filter : set) { - if ((filter.getFlags() & PackageManager.SET_BY_PROFILE_OWNER) != 0) { + if (filter.getOwnerPackage().equals(ownerPackage) + && filter.getOwnerUserId() == callingUserId) { resolver.removeFilter(filter); } } @@ -11644,6 +11693,29 @@ public class PackageManagerService extends IPackageManager.Stub { } } + // Enforcing that callingUid is owning pkg on userId + private void enforceOwnerRights(String pkg, int userId, int callingUid) { + // The system owns everything. + if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) { + return; + } + int callingUserId = UserHandle.getUserId(callingUid); + if (callingUserId != userId) { + throw new SecurityException("calling uid " + callingUid + + " pretends to own " + pkg + " on user " + userId + " but belongs to user " + + callingUserId); + } + PackageInfo pi = getPackageInfo(pkg, 0, callingUserId); + if (pi == null) { + throw new IllegalArgumentException("Unknown package " + pkg + " on user " + + callingUserId); + } + if (!UserHandle.isSameApp(pi.applicationInfo.uid, callingUid)) { + throw new SecurityException("Calling uid " + callingUid + + " does not own package " + pkg); + } + } + @Override public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) { Intent intent = new Intent(Intent.ACTION_MAIN); @@ -11667,6 +11739,47 @@ public class PackageManagerService extends IPackageManager.Stub { preferred.activityInfo.name); } + /** + * Check if calling UID is the current home app. This handles both the case + * where the user has selected a specific home app, and where there is only + * one home app. + */ + public boolean checkCallerIsHomeApp() { + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getCallingUserId(); + final List<ResolveInfo> allHomes = queryIntentActivities(intent, null, 0, callingUserId); + final ResolveInfo preferredHome = findPreferredActivity(intent, null, 0, allHomes, 0, true, + false, false, callingUserId); + + if (preferredHome != null) { + if (callingUid == preferredHome.activityInfo.applicationInfo.uid) { + return true; + } + } else { + for (ResolveInfo info : allHomes) { + if (callingUid == info.activityInfo.applicationInfo.uid) { + return true; + } + } + } + + return false; + } + + /** + * Enforce that calling UID is the current home app. This handles both the + * case where the user has selected a specific home app, and where there is + * only one home app. + */ + public void enforceCallerIsHomeApp() { + if (!checkCallerIsHomeApp()) { + throw new SecurityException("Caller is not currently selected home app"); + } + } + @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId, String callingPackage) { diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index e272f38275f4..2b4a24a768a1 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -110,8 +110,9 @@ final class Notifier { // True if a user activity message should be sent. private boolean mUserActivityPending; - // True if the screen on blocker has been acquired. - private boolean mScreenOnBlockerAcquired; + // The currently active screen on listener. This field is non-null whenever the + // ScreenOnBlocker has been acquired and we are awaiting a callback to release it. + private ScreenOnUnblocker mPendingScreenOnUnblocker; public Notifier(Looper looper, Context context, IBatteryStats batteryStats, IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker, @@ -255,15 +256,16 @@ final class Notifier { if (mActualPowerState != POWER_STATE_AWAKE) { mActualPowerState = POWER_STATE_AWAKE; mPendingWakeUpBroadcast = true; - if (!mScreenOnBlockerAcquired) { - mScreenOnBlockerAcquired = true; + if (mPendingScreenOnUnblocker == null) { mScreenOnBlocker.acquire(); } + final ScreenOnUnblocker unblocker = new ScreenOnUnblocker(); + mPendingScreenOnUnblocker = unblocker; mHandler.post(new Runnable() { @Override public void run() { EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0); - mPolicy.wakingUp(mScreenOnListener); + mPolicy.wakingUp(unblocker); mActivityManagerInternal.wakingUp(); } }); @@ -459,18 +461,17 @@ final class Notifier { } } - private final WindowManagerPolicy.ScreenOnListener mScreenOnListener = - new WindowManagerPolicy.ScreenOnListener() { + private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener { @Override public void onScreenOn() { synchronized (mLock) { - if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) { - mScreenOnBlockerAcquired = false; + if (mPendingScreenOnUnblocker == this) { + mPendingScreenOnUnblocker = null; mScreenOnBlocker.release(); } } } - }; + } private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() { @Override diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index dc44e51f6d05..463f76353367 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -18,9 +18,7 @@ package com.android.server.statusbar; import com.android.server.notification.NotificationDelegate; -import android.os.IBinder; -import android.service.notification.StatusBarNotification; - public interface StatusBarManagerInternal { void setNotificationDelegate(NotificationDelegate delegate); + void buzzBeepBlinked(); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index e548fa56d96c..d0013aaf2fd9 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -111,6 +111,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub public void setNotificationDelegate(NotificationDelegate delegate) { mNotificationDelegate = delegate; } + @Override + public void buzzBeepBlinked() { + if (mBar != null) { + try { + mBar.buzzBeepBlinked(); + } catch (RemoteException ex) { + } + } + } }; // ================================================================================ diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java index f18939fdfa51..51009affc4e8 100644 --- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java +++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java @@ -24,6 +24,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.os.SystemClock; import android.os.UserHandle; import android.util.Log; import android.util.Slog; @@ -41,6 +42,13 @@ public class TrustAgentWrapper { private static final int MSG_GRANT_TRUST = 1; private static final int MSG_REVOKE_TRUST = 2; private static final int MSG_TRUST_TIMEOUT = 3; + private static final int MSG_RESTART_TIMEOUT = 4; + + /** + * Time in uptime millis that we wait for the service connection, both when starting + * and when the service disconnects. + */ + private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000; /** * Long extra for {@link #MSG_GRANT_TRUST} @@ -53,6 +61,8 @@ public class TrustAgentWrapper { private final ComponentName mName; private ITrustAgentService mTrustAgentService; + private boolean mBound; + private long mScheduledRestartUptimeMillis; // Trust state private boolean mTrusted; @@ -95,6 +105,10 @@ public class TrustAgentWrapper { } mTrustManagerService.updateTrust(mUserId); break; + case MSG_RESTART_TIMEOUT: + unbind(); + mTrustManagerService.resetAgent(mName, mUserId); + break; } } }; @@ -123,6 +137,7 @@ public class TrustAgentWrapper { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString()); + mHandler.removeMessages(MSG_RESTART_TIMEOUT); mTrustAgentService = ITrustAgentService.Stub.asInterface(service); mTrustManagerService.mArchive.logAgentConnected(mUserId, name); setCallback(mCallback); @@ -134,6 +149,9 @@ public class TrustAgentWrapper { mTrustAgentService = null; mTrustManagerService.mArchive.logAgentDied(mUserId, name); mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); + if (mBound) { + scheduleRestart(); + } } }; @@ -144,9 +162,12 @@ public class TrustAgentWrapper { mTrustManagerService = trustManagerService; mUserId = user.getIdentifier(); mName = intent.getComponent(); - if (!context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user)) { - if (DEBUG) Log.v(TAG, "can't bind to TrustAgent " + mName.flattenToShortString()); - // TODO: retry somehow? + // Schedules a restart for when connecting times out. If the connection succeeds, + // the restart is canceled in mCallback's onConnected. + scheduleRestart(); + mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user); + if (!mBound) { + Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString()); } } @@ -184,14 +205,38 @@ public class TrustAgentWrapper { } public void unbind() { + if (!mBound) { + return; + } if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString()); mTrustManagerService.mArchive.logAgentStopped(mUserId, mName); mContext.unbindService(mConnection); + mBound = false; mTrustAgentService = null; mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); + mHandler.removeMessages(MSG_RESTART_TIMEOUT); } public boolean isConnected() { return mTrustAgentService != null; } + + public boolean isBound() { + return mBound; + } + + /** + * If not connected, returns the time at which the agent is restarted. + * + * @return restart time in uptime millis. + */ + public long getScheduledRestartUptimeMillis() { + return mScheduledRestartUptimeMillis; + } + + private void scheduleRestart() { + mHandler.removeMessages(MSG_RESTART_TIMEOUT); + mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS; + mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis); + } } diff --git a/services/core/java/com/android/server/trust/TrustArchive.java b/services/core/java/com/android/server/trust/TrustArchive.java index 56950d2f217a..5e32d86d27c0 100644 --- a/services/core/java/com/android/server/trust/TrustArchive.java +++ b/services/core/java/com/android/server/trust/TrustArchive.java @@ -130,7 +130,7 @@ public class TrustArchive { } } - private static String formatDuration(long duration) { + public static String formatDuration(long duration) { StringBuilder sb = new StringBuilder(); TimeUtils.formatDuration(duration, sb); return sb.toString(); diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 1aec56941c36..14436aad8e1b 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -45,6 +45,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.service.trust.TrustAgentService; @@ -99,12 +100,6 @@ public class TrustManagerService extends SystemService { private UserManager mUserManager; - /** - * Cache for {@link #refreshAgentList()} - */ - private final ArraySet<AgentInfo> mObsoleteAgents = new ArraySet<AgentInfo>(); - - public TrustManagerService(Context context) { super(context); mContext = context; @@ -168,8 +163,8 @@ public class TrustManagerService extends SystemService { List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); - mObsoleteAgents.clear(); - mObsoleteAgents.addAll(mActiveAgents); + ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>(); + obsoleteAgents.addAll(mActiveAgents); for (UserInfo userInfo : userInfos) { int disabledFeatures = lockPatternUtils.getDevicePolicyManager() @@ -208,14 +203,14 @@ public class TrustManagerService extends SystemService { new Intent().setComponent(name), userInfo.getUserHandle()); mActiveAgents.add(agentInfo); } else { - mObsoleteAgents.remove(agentInfo); + obsoleteAgents.remove(agentInfo); } } } boolean trustMayHaveChanged = false; - for (int i = 0; i < mObsoleteAgents.size(); i++) { - AgentInfo info = mObsoleteAgents.valueAt(i); + for (int i = 0; i < obsoleteAgents.size(); i++) { + AgentInfo info = obsoleteAgents.valueAt(i); if (info.agent.isTrusted()) { trustMayHaveChanged = true; } @@ -228,6 +223,43 @@ public class TrustManagerService extends SystemService { } } + private void removeAgentsOfPackage(String packageName) { + boolean trustMayHaveChanged = false; + for (int i = mActiveAgents.size() - 1; i >= 0; i--) { + AgentInfo info = mActiveAgents.valueAt(i); + if (packageName.equals(info.component.getPackageName())) { + Log.i(TAG, "Resetting agent " + info.component.flattenToShortString()); + if (info.agent.isTrusted()) { + trustMayHaveChanged = true; + } + info.agent.unbind(); + mActiveAgents.removeAt(i); + } + } + if (trustMayHaveChanged) { + updateTrustAll(); + } + } + + public void resetAgent(ComponentName name, int userId) { + boolean trustMayHaveChanged = false; + for (int i = mActiveAgents.size() - 1; i >= 0; i--) { + AgentInfo info = mActiveAgents.valueAt(i); + if (name.equals(info.component) && userId == info.userId) { + Log.i(TAG, "Resetting agent " + info.component.flattenToShortString()); + if (info.agent.isTrusted()) { + trustMayHaveChanged = true; + } + info.agent.unbind(); + mActiveAgents.removeAt(i); + } + } + if (trustMayHaveChanged) { + updateTrust(userId); + } + refreshAgentList(); + } + private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) { if (resolveInfo == null || resolveInfo.serviceInfo == null || resolveInfo.serviceInfo.metaData == null) return null; @@ -340,7 +372,7 @@ public class TrustManagerService extends SystemService { private void removeListener(ITrustListener listener) { for (int i = 0; i < mTrustListeners.size(); i++) { if (mTrustListeners.get(i).asBinder() == listener.asBinder()) { - mTrustListeners.get(i); + mTrustListeners.remove(i); return; } } @@ -448,11 +480,18 @@ public class TrustManagerService extends SystemService { if (info.userId != user.id) { continue; } boolean trusted = info.agent.isTrusted(); fout.print(" "); fout.println(info.component.flattenToShortString()); - fout.print(" connected=" + dumpBool(info.agent.isConnected())); + fout.print(" bound=" + dumpBool(info.agent.isBound())); + fout.print(", connected=" + dumpBool(info.agent.isConnected())); fout.println(", trusted=" + dumpBool(trusted)); if (trusted) { fout.println(" message=\"" + info.agent.getMessage() + "\""); } + if (!info.agent.isConnected()) { + String restartTime = TrustArchive.formatDuration( + info.agent.getScheduledRestartUptimeMillis() + - SystemClock.uptimeMillis()); + fout.println(" restartScheduledAt=" + restartTime); + } if (!simpleNames.add(TrustArchive.getSimpleName(info.component))) { duplicateSimpleNames = true; } @@ -501,6 +540,11 @@ public class TrustManagerService extends SystemService { // We're interested in all changes, even if just some components get enabled / disabled. return true; } + + @Override + public void onPackageDisappeared(String packageName, int reason) { + removeAgentsOfPackage(packageName); + } }; private class DevicePolicyReceiver extends BroadcastReceiver { diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 5808e2fc7a5f..1a9a85cc6630 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -205,9 +205,9 @@ public final class TvInputManagerService extends SystemService { }, UserHandle.ALL, intentFilter, null, null); } - private static boolean hasHardwarePermission(PackageManager pm, ComponentName name) { + private static boolean hasHardwarePermission(PackageManager pm, ComponentName component) { return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE, - name.getPackageName()) == PackageManager.PERMISSION_GRANTED; + component.getPackageName()) == PackageManager.PERMISSION_GRANTED; } private void buildTvInputListLocked(int userId) { @@ -231,15 +231,15 @@ public final class TvInputManagerService extends SystemService { } try { inputList.clear(); - ComponentName service = new ComponentName(si.packageName, si.name); - if (hasHardwarePermission(pm, service)) { - ServiceState serviceState = userState.serviceStateMap.get(service); + ComponentName component = new ComponentName(si.packageName, si.name); + if (hasHardwarePermission(pm, component)) { + ServiceState serviceState = userState.serviceStateMap.get(component); if (serviceState == null) { // We see this hardware TV input service for the first time; we need to // prepare the ServiceState object so that we can connect to the service and // let it add TvInputInfo objects to mInputList if there's any. - serviceState = new ServiceState(service, userId); - userState.serviceStateMap.put(service, serviceState); + serviceState = new ServiceState(component, userId); + userState.serviceStateMap.put(component, serviceState); } else { inputList.addAll(serviceState.mInputList); } @@ -258,7 +258,7 @@ public final class TvInputManagerService extends SystemService { } // Reconnect the service if existing input is updated. - updateServiceConnectionLocked(service, userId); + updateServiceConnectionLocked(component, userId); userState.packageSet.add(si.packageName); } catch (IOException | XmlPullParserException e) { @@ -346,11 +346,11 @@ public final class TvInputManagerService extends SystemService { return userState; } - private ServiceState getServiceStateLocked(ComponentName name, int userId) { + private ServiceState getServiceStateLocked(ComponentName component, int userId) { UserState userState = getUserStateLocked(userId); - ServiceState serviceState = userState.serviceStateMap.get(name); + ServiceState serviceState = userState.serviceStateMap.get(component); if (serviceState == null) { - throw new IllegalStateException("Service state not found for " + name + " (userId=" + throw new IllegalStateException("Service state not found for " + component + " (userId=" + userId + ")"); } return serviceState; @@ -396,9 +396,9 @@ public final class TvInputManagerService extends SystemService { // TODO: Find a way to maintain connection only when necessary. } - private void updateServiceConnectionLocked(ComponentName service, int userId) { + private void updateServiceConnectionLocked(ComponentName component, int userId) { UserState userState = getUserStateLocked(userId); - ServiceState serviceState = userState.serviceStateMap.get(service); + ServiceState serviceState = userState.serviceStateMap.get(component); if (serviceState == null) { return; } @@ -419,10 +419,10 @@ public final class TvInputManagerService extends SystemService { return; } if (DEBUG) { - Slog.d(TAG, "bindServiceAsUser(service=" + service + ", userId=" + userId + ")"); + Slog.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")"); } - Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(service); + Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component); // Binding service may fail if the service is updating. // In that case, the connection will be revived in buildTvInputListLocked called by // onSomePackagesChanged. @@ -432,10 +432,10 @@ public final class TvInputManagerService extends SystemService { // This means that the service is already connected but its state indicates that we have // nothing to do with it. Then, disconnect the service. if (DEBUG) { - Slog.d(TAG, "unbindService(service=" + service + ")"); + Slog.d(TAG, "unbindService(service=" + component + ")"); } mContext.unbindService(serviceState.mConnection); - userState.serviceStateMap.remove(service); + userState.serviceStateMap.remove(component); } } @@ -693,45 +693,6 @@ public final class TvInputManagerService extends SystemService { updateServiceConnectionLocked(sessionState.mInfo.getComponent(), userId); } - private void unregisterClientInternalLocked(IBinder clientToken, String inputId, - int userId) { - UserState userState = getUserStateLocked(userId); - ClientState clientState = userState.clientStateMap.get(clientToken); - if (clientState != null) { - clientState.mInputIds.remove(inputId); - if (clientState.isEmpty()) { - userState.clientStateMap.remove(clientToken); - } - } - - TvInputInfo info = userState.inputMap.get(inputId).mInfo; - if (info == null) { - return; - } - ServiceState serviceState = userState.serviceStateMap.get(info.getComponent()); - if (serviceState == null) { - return; - } - - // Remove this client from the client list and unregister the callback. - serviceState.mClientTokens.remove(clientToken); - if (!serviceState.mClientTokens.isEmpty()) { - // We have other clients who want to keep the callback. Do this later. - return; - } - if (serviceState.mService == null || serviceState.mCallback == null) { - return; - } - try { - serviceState.mService.unregisterCallback(serviceState.mCallback); - } catch (RemoteException e) { - Slog.e(TAG, "error in unregisterCallback", e); - } finally { - serviceState.mCallback = null; - updateServiceConnectionLocked(info.getComponent(), userId); - } - } - private void notifyInputAddedLocked(UserState userState, String inputId) { if (DEBUG) { Slog.d(TAG, "notifyInputAdded: inputId = " + inputId); @@ -784,7 +745,7 @@ public final class TvInputManagerService extends SystemService { private void setStateLocked(String inputId, int state, int userId) { UserState userState = getUserStateLocked(userId); TvInputState inputState = userState.inputMap.get(inputId); - ServiceState serviceState = userState.serviceStateMap.get(inputId); + ServiceState serviceState = userState.serviceStateMap.get(inputState.mInfo.getComponent()); int oldState = inputState.mState; inputState.mState = state; if (serviceState != null && serviceState.mService == null @@ -1415,13 +1376,6 @@ public final class TvInputManagerService extends SystemService { pw.increaseIndent(); - pw.println("mInputIds:"); - pw.increaseIndent(); - for (String inputId : client.mInputIds) { - pw.println(inputId); - } - pw.decreaseIndent(); - pw.println("mSessionTokens:"); pw.increaseIndent(); for (IBinder token : client.mSessionTokens) { @@ -1545,7 +1499,6 @@ public final class TvInputManagerService extends SystemService { } private final class ClientState implements IBinder.DeathRecipient { - private final List<String> mInputIds = new ArrayList<String>(); private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); private IBinder mClientToken; @@ -1557,7 +1510,7 @@ public final class TvInputManagerService extends SystemService { } public boolean isEmpty() { - return mInputIds.isEmpty() && mSessionTokens.isEmpty(); + return mSessionTokens.isEmpty(); } @Override @@ -1565,17 +1518,13 @@ public final class TvInputManagerService extends SystemService { synchronized (mLock) { UserState userState = getUserStateLocked(mUserId); // DO NOT remove the client state of clientStateMap in this method. It will be - // removed in releaseSessionLocked() or unregisterClientInternalLocked(). + // removed in releaseSessionLocked(). ClientState clientState = userState.clientStateMap.get(mClientToken); if (clientState != null) { while (clientState.mSessionTokens.size() > 0) { releaseSessionLocked( clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId); } - while (clientState.mInputIds.size() > 0) { - unregisterClientInternalLocked( - mClientToken, clientState.mInputIds.get(0), mUserId); - } } mClientToken = null; } @@ -1586,7 +1535,7 @@ public final class TvInputManagerService extends SystemService { private final List<IBinder> mClientTokens = new ArrayList<IBinder>(); private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); private final ServiceConnection mConnection; - private final ComponentName mName; + private final ComponentName mComponent; private final boolean mIsHardware; private final List<TvInputInfo> mInputList = new ArrayList<TvInputInfo>(); @@ -1595,10 +1544,10 @@ public final class TvInputManagerService extends SystemService { private boolean mBound; private boolean mReconnecting; - private ServiceState(ComponentName name, int userId) { - mName = name; - mConnection = new InputServiceConnection(name, userId); - mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mName); + private ServiceState(ComponentName component, int userId) { + mComponent = component; + mConnection = new InputServiceConnection(component, userId); + mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mComponent); } } @@ -1639,27 +1588,27 @@ public final class TvInputManagerService extends SystemService { } private final class InputServiceConnection implements ServiceConnection { - private final ComponentName mName; + private final ComponentName mComponent; private final int mUserId; - private InputServiceConnection(ComponentName name, int userId) { - mName = name; + private InputServiceConnection(ComponentName component, int userId) { + mComponent = component; mUserId = userId; } @Override - public void onServiceConnected(ComponentName name, IBinder service) { + public void onServiceConnected(ComponentName component, IBinder service) { if (DEBUG) { - Slog.d(TAG, "onServiceConnected(name=" + name + ")"); + Slog.d(TAG, "onServiceConnected(component=" + component + ")"); } synchronized (mLock) { UserState userState = getUserStateLocked(mUserId); - ServiceState serviceState = userState.serviceStateMap.get(mName); + ServiceState serviceState = userState.serviceStateMap.get(mComponent); serviceState.mService = ITvInputService.Stub.asInterface(service); // Register a callback, if we need to. if (serviceState.mIsHardware && serviceState.mCallback == null) { - serviceState.mCallback = new ServiceCallback(mName, mUserId); + serviceState.mCallback = new ServiceCallback(mComponent, mUserId); try { serviceState.mService.registerCallback(serviceState.mCallback); } catch (RemoteException e) { @@ -1673,7 +1622,7 @@ public final class TvInputManagerService extends SystemService { } for (TvInputState inputState : userState.inputMap.values()) { - if (inputState.mInfo.getComponent().equals(name) + if (inputState.mInfo.getComponent().equals(component) && inputState.mState != INPUT_STATE_DISCONNECTED) { notifyInputStateChangedLocked(userState, inputState.mInfo.getId(), inputState.mState, null); @@ -1705,17 +1654,17 @@ public final class TvInputManagerService extends SystemService { } @Override - public void onServiceDisconnected(ComponentName name) { + public void onServiceDisconnected(ComponentName component) { if (DEBUG) { - Slog.d(TAG, "onServiceDisconnected(name=" + name + ")"); + Slog.d(TAG, "onServiceDisconnected(component=" + component + ")"); } - if (!mName.equals(name)) { + if (!mComponent.equals(component)) { throw new IllegalArgumentException("Mismatched ComponentName: " - + mName + " (expected), " + name + " (actual)."); + + mComponent + " (expected), " + component + " (actual)."); } synchronized (mLock) { UserState userState = getUserStateLocked(mUserId); - ServiceState serviceState = userState.serviceStateMap.get(mName); + ServiceState serviceState = userState.serviceStateMap.get(mComponent); if (serviceState != null) { serviceState.mReconnecting = true; serviceState.mBound = false; @@ -1733,25 +1682,25 @@ public final class TvInputManagerService extends SystemService { } for (TvInputState inputState : userState.inputMap.values()) { - if (inputState.mInfo.getComponent().equals(name)) { + if (inputState.mInfo.getComponent().equals(component)) { String inputId = inputState.mInfo.getId(); notifyInputStateChangedLocked(userState, inputId, INPUT_STATE_DISCONNECTED, null); userState.wrappedInputMap.remove(inputId); } } - updateServiceConnectionLocked(mName, mUserId); + updateServiceConnectionLocked(mComponent, mUserId); } } } } private final class ServiceCallback extends ITvInputServiceCallback.Stub { - private final ComponentName mName; + private final ComponentName mComponent; private final int mUserId; - ServiceCallback(ComponentName name, int userId) { - mName = name; + ServiceCallback(ComponentName component, int userId) { + mComponent = component; mUserId = userId; } @@ -1763,13 +1712,13 @@ public final class TvInputManagerService extends SystemService { } private void ensureValidInput(TvInputInfo inputInfo) { - if (inputInfo.getId() == null || !mName.equals(inputInfo.getComponent())) { + if (inputInfo.getId() == null || !mComponent.equals(inputInfo.getComponent())) { throw new IllegalArgumentException("Invalid TvInputInfo"); } } private void addTvInputLocked(TvInputInfo inputInfo) { - ServiceState serviceState = getServiceStateLocked(mName, mUserId); + ServiceState serviceState = getServiceStateLocked(mComponent, mUserId); serviceState.mInputList.add(inputInfo); buildTvInputListLocked(mUserId); } @@ -1798,7 +1747,7 @@ public final class TvInputManagerService extends SystemService { public void removeTvInput(String inputId) { ensureHardwarePermission(); synchronized (mLock) { - ServiceState serviceState = getServiceStateLocked(mName, mUserId); + ServiceState serviceState = getServiceStateLocked(mComponent, mUserId); boolean removed = false; for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator(); it.hasNext(); ) { @@ -1829,7 +1778,7 @@ public final class TvInputManagerService extends SystemService { } private boolean hasInputIdLocked(String inputId) { - ServiceState serviceState = getServiceStateLocked(mName, mUserId); + ServiceState serviceState = getServiceStateLocked(mComponent, mUserId); for (TvInputInfo inputInfo : serviceState.mInputList) { if (inputInfo.getId().equals(inputId)) { return true; diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java index 874e105eb8f3..9b69ce244ed9 100644 --- a/services/core/java/com/android/server/wm/AppWindowAnimator.java +++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java @@ -297,6 +297,13 @@ public class AppWindowAnimator { mAppToken.mLaunchTaskBehind = false; } else { mAppToken.updateReportedVisibilityLocked(); + if (mAppToken.mEnteringAnimation) { + mAppToken.mEnteringAnimation = false; + try { + mService.mActivityManager.notifyEnterAnimationComplete(mAppToken.token); + } catch (RemoteException e) { + } + } } return false; diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 312689ba340a..3fcd067a1710 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -110,6 +110,7 @@ class AppWindowToken extends WindowToken { boolean mDeferRemoval; boolean mLaunchTaskBehind; + boolean mEnteringAnimation; AppWindowToken(WindowManagerService _service, IApplicationToken _token, boolean _voiceInteraction) { diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java new file mode 100644 index 000000000000..64b852b9de06 --- /dev/null +++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java @@ -0,0 +1,149 @@ +/* + * 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.wm; + + + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.view.Display; +import android.view.Surface; +import android.view.Surface.OutOfResourcesException; +import android.view.SurfaceControl; +import android.view.SurfaceSession; +import android.util.Slog; + +class CircularDisplayMask { + private static final String TAG = "CircularDisplayMask"; + + private static final int STROKE_WIDTH = 2; + // size of the chin + private int mScreenOffset = 0; + // Display dimensions + private Point mScreenSize; + + private final SurfaceControl mSurfaceControl; + private final Surface mSurface = new Surface(); + private int mLastDW; + private int mLastDH; + private boolean mDrawNeeded; + private Paint mPaint; + private int mRotation; + private boolean mVisible; + private boolean mDimensionsUnequal = false; + + public CircularDisplayMask(Display display, SurfaceSession session, int zOrder, + int screenOffset) { + mScreenSize = new Point(); + display.getSize(mScreenSize); + if (mScreenSize.x != mScreenSize.y) { + Slog.w(TAG, "Screen dimensions of displayId = " + display.getDisplayId() + + "are not equal, circularMask will not be drawn."); + mDimensionsUnequal = true; + } + + SurfaceControl ctrl = null; + try { + ctrl = new SurfaceControl(session, "CircularDisplayMask", + mScreenSize.x, mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); + ctrl.setLayerStack(display.getLayerStack()); + ctrl.setLayer(zOrder); + ctrl.setPosition(0, 0); + ctrl.show(); + mSurface.copyFrom(ctrl); + } catch (OutOfResourcesException e) { + } + mSurfaceControl = ctrl; + mDrawNeeded = true; + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(Color.BLACK); + mPaint.setStrokeWidth(STROKE_WIDTH); + mScreenOffset = screenOffset; + } + + private void drawIfNeeded() { + if (!mDrawNeeded || !mVisible || mDimensionsUnequal) { + return; + } + mDrawNeeded = false; + + Rect dirty = new Rect(0, 0, mScreenSize.x, mScreenSize.y); + Canvas c = null; + try { + c = mSurface.lockCanvas(dirty); + } catch (IllegalArgumentException e) { + } catch (Surface.OutOfResourcesException e) { + } + if (c == null) { + return; + } + c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC); + switch (mRotation) { + case Surface.ROTATION_0: + case Surface.ROTATION_90: + // chin bottom or right + mSurfaceControl.setPosition(0, 0); + break; + case Surface.ROTATION_180: + // chin top + mSurfaceControl.setPosition(0, -mScreenOffset); + break; + case Surface.ROTATION_270: + // chin left + mSurfaceControl.setPosition(-mScreenOffset, 0); + break; + } + + int circleRadius = mScreenSize.x / 2; + c.drawCircle(circleRadius, circleRadius, circleRadius, mPaint); + mSurface.unlockCanvasAndPost(c); + } + + // Note: caller responsible for being inside + // Surface.openTransaction() / closeTransaction() + public void setVisibility(boolean on) { + if (mSurfaceControl == null) { + return; + } + mVisible = on; + drawIfNeeded(); + if (on) { + mSurfaceControl.show(); + } else { + mSurfaceControl.hide(); + } + } + + void positionSurface(int dw, int dh, int rotation) { + if (mLastDW == dw && mLastDH == dh && mRotation == rotation) { + return; + } + mLastDW = dw; + mLastDH = dh; + mDrawNeeded = true; + mRotation = rotation; + drawIfNeeded(); + } + +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index eac2819077f0..670ba55fe577 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -440,6 +440,7 @@ public class WindowManagerService extends IWindowManager.Stub final SurfaceSession mFxSession; Watermark mWatermark; StrictModeFlash mStrictModeFlash; + CircularDisplayMask mCircularDisplayMask; FocusedStackFrame mFocusedStackFrame; int mFocusedStackLayer; @@ -853,6 +854,8 @@ public class WindowManagerService extends IWindowManager.Stub } finally { SurfaceControl.closeTransaction(); } + + showCircularDisplayMaskIfNeeded(); } public InputMonitor getInputMonitor() { @@ -4447,6 +4450,7 @@ public class WindowManagerService extends IWindowManager.Stub if (visible) { mOpeningApps.add(wtoken); wtoken.startingMoved = false; + wtoken.mEnteringAnimation = true; // If the token is currently hidden (should be the // common case), then we need to set up to wait for @@ -4469,6 +4473,7 @@ public class WindowManagerService extends IWindowManager.Stub } } else { mClosingApps.add(wtoken); + wtoken.mEnteringAnimation = false; // If the token is currently visible (should be the // common case), then set up to wait for it to be hidden. @@ -5647,6 +5652,44 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void showCircularDisplayMaskIfNeeded() { + // we're fullscreen and not hosted in an ActivityView + if (mContext.getResources().getBoolean( + com.android.internal.R.bool.config_windowIsRound) + && mContext.getResources().getBoolean( + com.android.internal.R.bool.config_windowShowCircularMask)) { + mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK)); + } + } + + public void showCircularMask() { + synchronized(mWindowMap) { + + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + ">>> OPEN TRANSACTION showDisplayMask"); + SurfaceControl.openTransaction(); + try { + // TODO(multi-display): support multiple displays + if (mCircularDisplayMask == null) { + int screenOffset = (int) mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.circular_display_mask_offset); + + mCircularDisplayMask = new CircularDisplayMask( + getDefaultDisplayContentLocked().getDisplay(), + mFxSession, + mPolicy.windowTypeToLayerLw( + WindowManager.LayoutParams.TYPE_POINTER) + * TYPE_LAYER_MULTIPLIER + 10, screenOffset); + } + mCircularDisplayMask.setVisibility(true); + } finally { + SurfaceControl.closeTransaction(); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + "<<< CLOSE TRANSACTION showDisplayMask"); + } + } + } + // TODO: more accounting of which pid(s) turned it on, keep count, // only allow disables from pids which have count on, etc. @Override @@ -7252,6 +7295,8 @@ public class WindowManagerService extends IWindowManager.Stub public static final int UPDATE_SCRN_CAP = 35; + public static final int SHOW_DISPLAY_MASK = 36; + @Override public void handleMessage(Message msg) { if (DEBUG_WINDOW_TRACE) { @@ -7646,6 +7691,11 @@ public class WindowManagerService extends IWindowManager.Stub break; } + case SHOW_DISPLAY_MASK: { + showCircularMask(); + break; + } + case DO_ANIMATION_CALLBACK: { try { ((IRemoteCallback)msg.obj).sendResult(null); @@ -9168,6 +9218,9 @@ public class WindowManagerService extends IWindowManager.Stub if (mStrictModeFlash != null) { mStrictModeFlash.positionSurface(defaultDw, defaultDh); } + if (mCircularDisplayMask != null) { + mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation); + } boolean focusDisplayed = false; diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 5599760c6596..9a4d90027db6 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -10,7 +10,6 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \ $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \ $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \ $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \ $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \ diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp deleted file mode 100644 index a6d929730683..000000000000 --- a/services/core/jni/com_android_server_dreams_McuHal.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "McuHal" - -//#define LOG_NDEBUG 0 - -#include "JNIHelp.h" -#include "jni.h" - -#include <ScopedUtfChars.h> -#include <ScopedPrimitiveArray.h> - -#include <utils/Errors.h> -#include <utils/Log.h> -#include <hardware/mcu.h> - -namespace android { - -static jlong nativeOpen(JNIEnv* env, jclass clazz) { - mcu_module_t* module = NULL; - status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID, - (hw_module_t const**)&module); - if (err) { - ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err)); - return 0; - } - - err = module->init(module); - if (err) { - ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err)); - return 0; - } - - return reinterpret_cast<jlong>(module); -} - -static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz, - jlong ptr, jstring msgStr, jbyteArray argArray) { - mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr); - - ScopedUtfChars msg(env, msgStr); - ALOGV("Sending message %s to MCU", msg.c_str()); - - void* result = NULL; - size_t resultSize = 0; - status_t err; - if (argArray) { - ScopedByteArrayRO arg(env, argArray); - err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(), - &result, &resultSize); - } else { - err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize); - } - if (err) { - ALOGE("Couldn't send message to MCU (%s)", strerror(-err)); - return NULL; - } - - if (!result) { - return NULL; - } - - jbyteArray resultArray = env->NewByteArray(resultSize); - if (resultArray) { - env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result)); - } - free(result); - return resultArray; -} - -static JNINativeMethod gMcuHalMethods[] = { - /* name, signature, funcPtr */ - { "nativeOpen", "()J", - (void*) nativeOpen }, - { "nativeSendMessage", "(JLjava/lang/String;[B)[B", - (void*) nativeSendMessage }, -}; - -int register_android_server_dreams_McuHal(JNIEnv* env) { - int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal", - gMcuHalMethods, NELEM(gMcuHalMethods)); - LOG_FATAL_IF(res < 0, "Unable to register native methods."); - return 0; -} - -} /* namespace android */ diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp index 47f83d019024..5c557b6e7c9a 100644 --- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp @@ -18,8 +18,8 @@ #define LOG_NDEBUG 1 -#include "JNIHelp.h" -#include "ScopedPrimitiveArray.h" +#include <JNIHelp.h> +#include <ScopedPrimitiveArray.h> #include <cstring> diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index bf7501ed5353..ce2ca9b5be36 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -37,7 +37,6 @@ int register_android_server_VibratorService(JNIEnv* env); int register_android_server_location_GpsLocationProvider(JNIEnv* env); int register_android_server_location_FlpHardwareProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); -int register_android_server_dreams_McuHal(JNIEnv* env); int register_android_server_hdmi_HdmiCecController(JNIEnv* env); int register_android_server_hdmi_HdmiMhlController(JNIEnv* env); int register_android_server_tv_TvInputHal(JNIEnv* env); @@ -73,7 +72,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_connectivity_Vpn(env); register_android_server_AssetAtlasService(env); register_android_server_ConsumerIrService(env); - register_android_server_dreams_McuHal(env); register_android_server_BatteryStatsService(env); register_android_server_hdmi_HdmiCecController(env); register_android_server_hdmi_HdmiMhlController(env); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e0612eb2e0e8..25f9e9b67c5e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -252,8 +252,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } }; - private IAppOpsService mAppOpsService; - static class ActiveAdmin { private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features"; private static final String TAG_DISABLE_CAMERA = "disable-camera"; @@ -1288,24 +1286,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getUserData(UserHandle.USER_OWNER); loadDeviceOwner(); cleanUpOldUsers(); - mAppOpsService = IAppOpsService.Stub.asInterface( - ServiceManager.getService(Context.APP_OPS_SERVICE)); - if (mDeviceOwner != null) { - if (mDeviceOwner.hasDeviceOwner()) { - try { - mAppOpsService.setDeviceOwner(mDeviceOwner.getDeviceOwnerPackageName()); - } catch (RemoteException e) { - Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e); - } - } - for (Integer i : mDeviceOwner.getProfileOwnerKeys()) { - try { - mAppOpsService.setProfileOwner(mDeviceOwner.getProfileOwnerPackageName(i), i); - } catch (RemoteException e) { - Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e); - } - } - } // Register an observer for watching for user setup complete. new SetupContentObserver(mHandler).register(mContext.getContentResolver()); // Initialize the user setup state, to handle the upgrade case. @@ -3169,14 +3149,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "Trying to set device owner but device owner is already set."); } - long token = Binder.clearCallingIdentity(); - try { - mAppOpsService.setDeviceOwner(packageName); - } catch (RemoteException e) { - Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e); - } finally { - Binder.restoreCallingIdentity(token); - } if (mDeviceOwner == null) { // Device owner is not set and does not exist, set it. mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName); @@ -3284,14 +3256,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalStateException( "Trying to set profile owner but user is already set-up."); } - long token = Binder.clearCallingIdentity(); - try { - mAppOpsService.setProfileOwner(packageName, userHandle); - } catch (RemoteException e) { - Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e); - } finally { - Binder.restoreCallingIdentity(token); - } + if (mDeviceOwner == null) { // Device owner state does not exist, create it. mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName, @@ -3606,12 +3571,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = Binder.clearCallingIdentity(); try { if ((flags & DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED) != 0) { - pm.addCrossProfileIntentFilter(filter, callingUserId, UserHandle.USER_OWNER, - PackageManager.SET_BY_PROFILE_OWNER); + pm.addCrossProfileIntentFilter(filter, who.getPackageName(), + mContext.getUserId(), callingUserId, UserHandle.USER_OWNER, 0); } if ((flags & DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT) != 0) { - pm.addCrossProfileIntentFilter(filter, UserHandle.USER_OWNER, callingUserId, - PackageManager.SET_BY_PROFILE_OWNER); + pm.addCrossProfileIntentFilter(filter, who.getPackageName(), + mContext.getUserId(), UserHandle.USER_OWNER, callingUserId, 0); } } catch (RemoteException re) { // Shouldn't happen @@ -3631,10 +3596,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { IPackageManager pm = AppGlobals.getPackageManager(); long id = Binder.clearCallingIdentity(); try { - pm.clearCrossProfileIntentFilters(callingUserId); + pm.clearCrossProfileIntentFilters(callingUserId, who.getPackageName(), + callingUserId); // If we want to support multiple managed profiles, we will have to only remove // those that have callingUserId as their target. - pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER); + pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER, who.getPackageName(), + callingUserId); } catch (RemoteException re) { // Shouldn't happen } finally { @@ -4291,9 +4258,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (Settings.Secure.getIntForUser(resolver, Settings.Secure.USER_SETUP_COMPLETE, 0, userHandle) != 0) { DevicePolicyData policy = getUserData(userHandle); - policy.mUserSetupComplete = true; - synchronized (this) { - saveSettingsLocked(userHandle); + if (!policy.mUserSetupComplete) { + policy.mUserSetupComplete = true; + synchronized (this) { + saveSettingsLocked(userHandle); + } } } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index bf2edc86867e..70266ee0c21e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -352,6 +352,9 @@ public final class SystemServer { mFirstBoot = mPackageManagerService.isFirstBoot(); mPackageManager = mSystemContext.getPackageManager(); + Slog.i(TAG, "User Service"); + ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance()); + // Initialize attribute cache used to cache resources from packages. AttributeCache.init(mSystemContext); @@ -434,10 +437,6 @@ public final class SystemServer { Slog.i(TAG, "Entropy Mixer"); ServiceManager.addService("entropy", new EntropyMixer(context)); - Slog.i(TAG, "User Service"); - ServiceManager.addService(Context.USER_SERVICE, - UserManagerService.getInstance()); - mContentResolver = context.getContentResolver(); // The AccountManager must come before the ContentService @@ -674,6 +673,8 @@ public final class SystemServer { mSystemServiceManager.startService( "com.android.server.wifi.WifiScanningService"); + mSystemServiceManager.startService("com.android.server.wifi.RttService"); + if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET)) { mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS); } @@ -930,7 +931,9 @@ public final class SystemServer { mSystemServiceManager.startService(HdmiControlService.class); } - mSystemServiceManager.startService(TvInputManagerService.class); + if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { + mSystemServiceManager.startService(TvInputManagerService.class); + } if (!disableNonCoreServices) { try { diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 4018deff7f1b..1c20d5d834a1 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -19,52 +19,56 @@ package com.android.server.usage; import android.Manifest; import android.app.AppOpsManager; import android.app.usage.IUsageStatsManager; -import android.app.usage.PackageUsageStats; -import android.app.usage.TimeSparseArray; import android.app.usage.UsageStats; import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.os.Binder; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.UserHandle; +import android.os.UserManager; import android.util.ArraySet; import android.util.Slog; +import android.util.SparseArray; + import com.android.internal.os.BackgroundThread; import com.android.server.SystemService; import java.io.File; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Calendar; +import java.util.Arrays; +import java.util.List; -public class UsageStatsService extends SystemService { +public class UsageStatsService extends SystemService implements + UserUsageStatsService.StatsUpdatedListener { static final String TAG = "UsageStatsService"; static final boolean DEBUG = false; private static final long TEN_SECONDS = 10 * 1000; private static final long TWENTY_MINUTES = 20 * 60 * 1000; private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES; - private static final int USAGE_STAT_RESULT_LIMIT = 10; - private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + static final int USAGE_STAT_RESULT_LIMIT = 10; // Handler message types. static final int MSG_REPORT_EVENT = 0; static final int MSG_FLUSH_TO_DISK = 1; + static final int MSG_REMOVE_USER = 2; - final Object mLock = new Object(); + private final Object mLock = new Object(); Handler mHandler; AppOpsManager mAppOps; + UserManager mUserManager; - private UsageStatsDatabase mDatabase; - private UsageStats[] mCurrentStats = new UsageStats[UsageStatsManager.BUCKET_COUNT]; - private TimeSparseArray<UsageStats.Event> mCurrentEvents = new TimeSparseArray<>(); - private boolean mStatsChanged = false; - private Calendar mDailyExpiryDate; + private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>(); + private File mUsageStatsDir; public UsageStatsService(Context context) { super(context); @@ -72,115 +76,96 @@ public class UsageStatsService extends SystemService { @Override public void onStart() { - mDailyExpiryDate = Calendar.getInstance(); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); + mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); mHandler = new H(BackgroundThread.get().getLooper()); File systemDataDir = new File(Environment.getDataDirectory(), "system"); - mDatabase = new UsageStatsDatabase(new File(systemDataDir, "usagestats")); - mDatabase.init(); + mUsageStatsDir = new File(systemDataDir, "usagestats"); + mUsageStatsDir.mkdirs(); + if (!mUsageStatsDir.exists()) { + throw new IllegalStateException("Usage stats directory does not exist: " + + mUsageStatsDir.getAbsolutePath()); + } + + getContext().registerReceiver(new UserRemovedReceiver(), + new IntentFilter(Intent.ACTION_USER_REMOVED)); synchronized (mLock) { - initLocked(); + cleanUpRemovedUsersLocked(); } publishLocalService(UsageStatsManagerInternal.class, new LocalService()); publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService()); } - private void initLocked() { - int nullCount = 0; - for (int i = 0; i < mCurrentStats.length; i++) { - mCurrentStats[i] = mDatabase.getLatestUsageStats(i); - if (mCurrentStats[i] == null) { - nullCount++; + private class UserRemovedReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (intent != null && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) { + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (userId >= 0) { + mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget(); + } } } + } - if (nullCount > 0) { - if (nullCount != mCurrentStats.length) { - // This is weird, but we shouldn't fail if something like this - // happens. - Slog.w(TAG, "Some stats have no latest available"); - } else { - // This must be first boot. - } + @Override + public void onStatsUpdated() { + mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL); + } - // By calling loadActiveStatsLocked, we will - // generate new stats for each bucket. - loadActiveStatsLocked(); - } else { - // Set up the expiry date to be one day from the latest daily stat. - // This may actually be today and we will rollover on the first event - // that is reported. - mDailyExpiryDate.setTimeInMillis( - mCurrentStats[UsageStatsManager.DAILY_BUCKET].mBeginTimeStamp); - mDailyExpiryDate.add(Calendar.DAY_OF_YEAR, 1); - UsageStatsUtils.truncateDateTo(UsageStatsManager.DAILY_BUCKET, mDailyExpiryDate); - Slog.i(TAG, "Rollover scheduled for " + sDateFormat.format(mDailyExpiryDate.getTime())); + private void cleanUpRemovedUsersLocked() { + final List<UserInfo> users = mUserManager.getUsers(true); + if (users == null || users.size() == 0) { + throw new IllegalStateException("There can't be no users"); } - // Now close off any events that were open at the time this was saved. - for (UsageStats stat : mCurrentStats) { - final int pkgCount = stat.getPackageCount(); - for (int i = 0; i < pkgCount; i++) { - PackageUsageStats pkgStats = stat.getPackage(i); - if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND || - pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) { - updateStatsLocked(stat, pkgStats.mPackageName, stat.mLastTimeSaved, - UsageStats.Event.END_OF_DAY); - notifyStatsChangedLocked(); - } - } + ArraySet<String> toDelete = new ArraySet<>(); + String[] fileNames = mUsageStatsDir.list(); + if (fileNames == null) { + // No users to delete. + return; } - } - private void rolloverStatsLocked() { - final long startTime = System.currentTimeMillis(); - Slog.i(TAG, "Rolling over usage stats"); - - // Finish any ongoing events with an END_OF_DAY event. Make a note of which components - // need a new CONTINUE_PREVIOUS_DAY entry. - ArraySet<String> continuePreviousDay = new ArraySet<>(); - for (UsageStats stat : mCurrentStats) { - final int pkgCount = stat.getPackageCount(); - for (int i = 0; i < pkgCount; i++) { - PackageUsageStats pkgStats = stat.getPackage(i); - if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND || - pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) { - continuePreviousDay.add(pkgStats.mPackageName); - updateStatsLocked(stat, pkgStats.mPackageName, - mDailyExpiryDate.getTimeInMillis() - 1, UsageStats.Event.END_OF_DAY); - mStatsChanged = true; - } - } + toDelete.addAll(Arrays.asList(fileNames)); + + final int userCount = users.size(); + for (int i = 0; i < userCount; i++) { + final UserInfo userInfo = users.get(i); + toDelete.remove(Integer.toString(userInfo.id)); } - persistActiveStatsLocked(); - mDatabase.prune(); - loadActiveStatsLocked(); - - final int continueCount = continuePreviousDay.size(); - for (int i = 0; i < continueCount; i++) { - String name = continuePreviousDay.valueAt(i); - for (UsageStats stat : mCurrentStats) { - updateStatsLocked(stat, name, - mCurrentStats[UsageStatsManager.DAILY_BUCKET].mBeginTimeStamp, - UsageStats.Event.CONTINUE_PREVIOUS_DAY); - mStatsChanged = true; + final int deleteCount = toDelete.size(); + for (int i = 0; i < deleteCount; i++) { + deleteRecursively(new File(mUsageStatsDir, toDelete.valueAt(i))); + } + } + + private static void deleteRecursively(File f) { + File[] files = f.listFiles(); + if (files != null) { + for (File subFile : files) { + deleteRecursively(subFile); } } - persistActiveStatsLocked(); - final long totalTime = System.currentTimeMillis() - startTime; - Slog.i(TAG, "Rolling over usage stats complete. Took " + totalTime + " milliseconds"); + if (!f.delete()) { + Slog.e(TAG, "Failed to delete " + f); + } } - private void notifyStatsChangedLocked() { - if (!mStatsChanged) { - mStatsChanged = true; - mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL); + private UserUsageStatsService getUserDataAndInitializeIfNeededLocked(int userId) { + UserUsageStatsService service = mUserState.get(userId); + if (service == null) { + service = new UserUsageStatsService(userId, + new File(mUsageStatsDir, Integer.toString(userId)), this); + service.init(); + mUserState.put(userId, service); } + return service; } /** @@ -189,58 +174,45 @@ public class UsageStatsService extends SystemService { void shutdown() { synchronized (mLock) { mHandler.removeMessages(MSG_REPORT_EVENT); - mHandler.removeMessages(MSG_FLUSH_TO_DISK); - persistActiveStatsLocked(); + flushToDiskLocked(); } } - private static String eventToString(int eventType) { - switch (eventType) { - case UsageStats.Event.NONE: - return "NONE"; - case UsageStats.Event.MOVE_TO_BACKGROUND: - return "MOVE_TO_BACKGROUND"; - case UsageStats.Event.MOVE_TO_FOREGROUND: - return "MOVE_TO_FOREGROUND"; - case UsageStats.Event.END_OF_DAY: - return "END_OF_DAY"; - case UsageStats.Event.CONTINUE_PREVIOUS_DAY: - return "CONTINUE_PREVIOUS_DAY"; - default: - return "UNKNOWN"; + /** + * Called by the Binder stub. + */ + void reportEvent(UsageStats.Event event, int userId) { + synchronized (mLock) { + final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId); + service.reportEvent(event); } } /** * Called by the Binder stub. */ - void reportEvent(UsageStats.Event event) { + void flushToDisk() { synchronized (mLock) { - if (DEBUG) { - Slog.d(TAG, "Got usage event for " + event.packageName - + "[" + event.timeStamp + "]: " - + eventToString(event.eventType)); - } - - if (event.timeStamp >= mDailyExpiryDate.getTimeInMillis()) { - // Need to rollover - rolloverStatsLocked(); - } - - mCurrentEvents.append(event.timeStamp, event); + flushToDiskLocked(); + } + } - for (UsageStats stats : mCurrentStats) { - updateStatsLocked(stats, event.packageName, event.timeStamp, event.eventType); - } - notifyStatsChangedLocked(); + /** + * Called by the Binder stub. + */ + void removeUser(int userId) { + synchronized (mLock) { + Slog.i(TAG, "Removing user " + userId + " and all data."); + mUserState.remove(userId); + cleanUpRemovedUsersLocked(); } } /** * Called by the Binder stub. */ - UsageStats[] getUsageStats(int bucketType, long beginTime) { - if (bucketType < 0 || bucketType >= mCurrentStats.length) { + UsageStats[] getUsageStats(int userId, int bucketType, long beginTime) { + if (bucketType < 0 || bucketType >= UsageStatsManager.BUCKET_COUNT) { return UsageStats.EMPTY_STATS; } @@ -250,110 +222,26 @@ public class UsageStatsService extends SystemService { } synchronized (mLock) { - if (beginTime >= mCurrentStats[bucketType].mEndTimeStamp) { - if (DEBUG) { - Slog.d(TAG, "Requesting stats after " + beginTime + " but latest is " - + mCurrentStats[bucketType].mEndTimeStamp); - } - // Nothing newer available. - return UsageStats.EMPTY_STATS; - } else if (beginTime >= mCurrentStats[bucketType].mBeginTimeStamp) { - if (DEBUG) { - Slog.d(TAG, "Returning in-memory stats"); - } - // Fast path for retrieving in-memory state. - // TODO(adamlesinski): This copy just to parcel the object is wasteful. - // It would be nice to parcel it here and send that back, but the Binder API - // would need to change. - return new UsageStats[] { new UsageStats(mCurrentStats[bucketType]) }; - } else { - // Flush any changes that were made to disk before we do a disk query. - persistActiveStatsLocked(); - } + UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId); + return service.getUsageStats(bucketType, beginTime); } - - if (DEBUG) { - Slog.d(TAG, "SELECT * FROM " + bucketType + " WHERE beginTime >= " - + beginTime + " LIMIT " + USAGE_STAT_RESULT_LIMIT); - } - - UsageStats[] results = mDatabase.getUsageStats(bucketType, beginTime, - USAGE_STAT_RESULT_LIMIT); - - if (DEBUG) { - Slog.d(TAG, "Results: " + results.length); - } - return results; } /** * Called by the Binder stub. */ - UsageStats.Event[] getEvents(long time) { + UsageStats.Event[] getEvents(int userId, long time) { return UsageStats.Event.EMPTY_EVENTS; } - private void loadActiveStatsLocked() { - final long timeNow = System.currentTimeMillis(); - - Calendar tempCal = mDailyExpiryDate; - for (int i = 0; i < mCurrentStats.length; i++) { - tempCal.setTimeInMillis(timeNow); - UsageStatsUtils.truncateDateTo(i, tempCal); - - if (mCurrentStats[i] != null && - mCurrentStats[i].mBeginTimeStamp == tempCal.getTimeInMillis()) { - // These are the same, no need to load them (in memory stats are always newer - // than persisted stats). - continue; - } - - UsageStats[] stats = mDatabase.getUsageStats(i, timeNow, 1); - if (stats != null && stats.length > 0) { - mCurrentStats[i] = stats[stats.length - 1]; - } else { - mCurrentStats[i] = UsageStats.create(tempCal.getTimeInMillis(), timeNow); - } + private void flushToDiskLocked() { + final int userCount = mUserState.size(); + for (int i = 0; i < userCount; i++) { + UserUsageStatsService service = mUserState.valueAt(i); + service.persistActiveStats(); } - mStatsChanged = false; - mDailyExpiryDate.setTimeInMillis(timeNow); - mDailyExpiryDate.add(Calendar.DAY_OF_YEAR, 1); - UsageStatsUtils.truncateDateTo(UsageStatsManager.DAILY_BUCKET, mDailyExpiryDate); - Slog.i(TAG, "Rollover scheduled for " + sDateFormat.format(mDailyExpiryDate.getTime())); - } - - private void persistActiveStatsLocked() { - if (mStatsChanged) { - Slog.i(TAG, "Flushing usage stats to disk"); - try { - for (int i = 0; i < mCurrentStats.length; i++) { - mDatabase.putUsageStats(i, mCurrentStats[i]); - } - mStatsChanged = false; - mHandler.removeMessages(MSG_FLUSH_TO_DISK); - } catch (IOException e) { - Slog.e(TAG, "Failed to persist active stats", e); - } - } - } - - private void updateStatsLocked(UsageStats stats, String packageName, long timeStamp, - int eventType) { - PackageUsageStats pkgStats = stats.getOrCreatePackageUsageStats(packageName); - - // TODO(adamlesinski): Ensure that we recover from incorrect event sequences - // like double MOVE_TO_BACKGROUND, etc. - if (eventType == UsageStats.Event.MOVE_TO_BACKGROUND || - eventType == UsageStats.Event.END_OF_DAY) { - if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND || - pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) { - pkgStats.mTotalTimeSpent += timeStamp - pkgStats.mLastTimeUsed; - } - } - pkgStats.mLastEvent = eventType; - pkgStats.mLastTimeUsed = timeStamp; - stats.mEndTimeStamp = timeStamp; + mHandler.removeMessages(MSG_FLUSH_TO_DISK); } class H extends Handler { @@ -365,13 +253,15 @@ public class UsageStatsService extends SystemService { public void handleMessage(Message msg) { switch (msg.what) { case MSG_REPORT_EVENT: - reportEvent((UsageStats.Event) msg.obj); + reportEvent((UsageStats.Event) msg.obj, msg.arg1); break; case MSG_FLUSH_TO_DISK: - synchronized (mLock) { - persistActiveStatsLocked(); - } + flushToDisk(); + break; + + case MSG_REMOVE_USER: + removeUser(msg.arg1); break; default: @@ -401,9 +291,10 @@ public class UsageStatsService extends SystemService { return UsageStats.EMPTY_STATS; } - long token = Binder.clearCallingIdentity(); + final int userId = UserHandle.getCallingUserId(); + final long token = Binder.clearCallingIdentity(); try { - return getUsageStats(bucketType, time); + return getUsageStats(userId, bucketType, time); } finally { Binder.restoreCallingIdentity(token); } @@ -415,9 +306,10 @@ public class UsageStatsService extends SystemService { return UsageStats.Event.EMPTY_EVENTS; } - long token = Binder.clearCallingIdentity(); + final int userId = UserHandle.getCallingUserId(); + final long token = Binder.clearCallingIdentity(); try { - return getEvents(time); + return getEvents(userId, time); } finally { Binder.restoreCallingIdentity(token); } @@ -432,10 +324,11 @@ public class UsageStatsService extends SystemService { private class LocalService extends UsageStatsManagerInternal { @Override - public void reportEvent(ComponentName component, long timeStamp, int eventType) { + public void reportEvent(ComponentName component, int userId, + long timeStamp, int eventType) { UsageStats.Event event = new UsageStats.Event(component.getPackageName(), timeStamp, eventType); - mHandler.obtainMessage(MSG_REPORT_EVENT, event).sendToTarget(); + mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @Override diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java new file mode 100644 index 000000000000..d12418883964 --- /dev/null +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -0,0 +1,275 @@ +package com.android.server.usage; + +import android.app.usage.PackageUsageStats; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.util.ArraySet; +import android.util.Slog; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; + +/** + * A per-user UsageStatsService. All methods are meant to be called with the main lock held + * in UsageStatsService. + */ +class UserUsageStatsService { + private static final String TAG = "UsageStatsService"; + private static final boolean DEBUG = UsageStatsService.DEBUG; + private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + private final UsageStatsDatabase mDatabase; + private final UsageStats[] mCurrentStats = new UsageStats[UsageStatsManager.BUCKET_COUNT]; + private boolean mStatsChanged = false; + private final Calendar mDailyExpiryDate; + private final StatsUpdatedListener mListener; + private final String mLogPrefix; + + interface StatsUpdatedListener { + void onStatsUpdated(); + } + + UserUsageStatsService(int userId, File usageStatsDir, StatsUpdatedListener listener) { + mDailyExpiryDate = Calendar.getInstance(); + mDatabase = new UsageStatsDatabase(usageStatsDir); + mListener = listener; + mLogPrefix = "User[" + Integer.toString(userId) + "] "; + } + + void init() { + mDatabase.init(); + + int nullCount = 0; + for (int i = 0; i < mCurrentStats.length; i++) { + mCurrentStats[i] = mDatabase.getLatestUsageStats(i); + if (mCurrentStats[i] == null) { + nullCount++; + } + } + + if (nullCount > 0) { + if (nullCount != mCurrentStats.length) { + // This is weird, but we shouldn't fail if something like this + // happens. + Slog.w(TAG, mLogPrefix + "Some stats have no latest available"); + } else { + // This must be first boot. + } + + // By calling loadActiveStats, we will + // generate new stats for each bucket. + loadActiveStats(); + } else { + // Set up the expiry date to be one day from the latest daily stat. + // This may actually be today and we will rollover on the first event + // that is reported. + mDailyExpiryDate.setTimeInMillis( + mCurrentStats[UsageStatsManager.DAILY_BUCKET].mBeginTimeStamp); + mDailyExpiryDate.add(Calendar.DAY_OF_YEAR, 1); + UsageStatsUtils.truncateDateTo(UsageStatsManager.DAILY_BUCKET, mDailyExpiryDate); + Slog.i(TAG, mLogPrefix + "Rollover scheduled for " + + sDateFormat.format(mDailyExpiryDate.getTime())); + } + + // Now close off any events that were open at the time this was saved. + for (UsageStats stat : mCurrentStats) { + final int pkgCount = stat.getPackageCount(); + for (int i = 0; i < pkgCount; i++) { + PackageUsageStats pkgStats = stat.getPackage(i); + if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND || + pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) { + updateStats(stat, pkgStats.mPackageName, stat.mLastTimeSaved, + UsageStats.Event.END_OF_DAY); + notifyStatsChanged(); + } + } + } + } + + void reportEvent(UsageStats.Event event) { + if (DEBUG) { + Slog.d(TAG, mLogPrefix + "Got usage event for " + event.packageName + + "[" + event.timeStamp + "]: " + + eventToString(event.eventType)); + } + + if (event.timeStamp >= mDailyExpiryDate.getTimeInMillis()) { + // Need to rollover + rolloverStats(); + } + + for (UsageStats stats : mCurrentStats) { + updateStats(stats, event.packageName, event.timeStamp, event.eventType); + } + + notifyStatsChanged(); + } + + UsageStats[] getUsageStats(int bucketType, long beginTime) { + if (beginTime >= mCurrentStats[bucketType].mEndTimeStamp) { + if (DEBUG) { + Slog.d(TAG, mLogPrefix + "Requesting stats after " + beginTime + " but latest is " + + mCurrentStats[bucketType].mEndTimeStamp); + } + // Nothing newer available. + return UsageStats.EMPTY_STATS; + + } else if (beginTime >= mCurrentStats[bucketType].mBeginTimeStamp) { + if (DEBUG) { + Slog.d(TAG, mLogPrefix + "Returning in-memory stats"); + } + // Fast path for retrieving in-memory state. + // TODO(adamlesinski): This copy just to parcel the object is wasteful. + // It would be nice to parcel it here and send that back, but the Binder API + // would need to change. + return new UsageStats[] { new UsageStats(mCurrentStats[bucketType]) }; + + } else { + // Flush any changes that were made to disk before we do a disk query. + persistActiveStats(); + } + + if (DEBUG) { + Slog.d(TAG, mLogPrefix + "SELECT * FROM " + bucketType + " WHERE beginTime >= " + + beginTime + " LIMIT " + UsageStatsService.USAGE_STAT_RESULT_LIMIT); + } + + final UsageStats[] results = mDatabase.getUsageStats(bucketType, beginTime, + UsageStatsService.USAGE_STAT_RESULT_LIMIT); + + if (DEBUG) { + Slog.d(TAG, mLogPrefix + "Results: " + results.length); + } + return results; + } + + void persistActiveStats() { + if (mStatsChanged) { + Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk"); + try { + for (int i = 0; i < mCurrentStats.length; i++) { + mDatabase.putUsageStats(i, mCurrentStats[i]); + } + mStatsChanged = false; + } catch (IOException e) { + Slog.e(TAG, mLogPrefix + "Failed to persist active stats", e); + } + } + } + + private void rolloverStats() { + final long startTime = System.currentTimeMillis(); + Slog.i(TAG, mLogPrefix + "Rolling over usage stats"); + + // Finish any ongoing events with an END_OF_DAY event. Make a note of which components + // need a new CONTINUE_PREVIOUS_DAY entry. + ArraySet<String> continuePreviousDay = new ArraySet<>(); + for (UsageStats stat : mCurrentStats) { + final int pkgCount = stat.getPackageCount(); + for (int i = 0; i < pkgCount; i++) { + PackageUsageStats pkgStats = stat.getPackage(i); + if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND || + pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) { + continuePreviousDay.add(pkgStats.mPackageName); + updateStats(stat, pkgStats.mPackageName, + mDailyExpiryDate.getTimeInMillis() - 1, UsageStats.Event.END_OF_DAY); + mStatsChanged = true; + } + } + } + + persistActiveStats(); + mDatabase.prune(); + loadActiveStats(); + + final int continueCount = continuePreviousDay.size(); + for (int i = 0; i < continueCount; i++) { + String name = continuePreviousDay.valueAt(i); + for (UsageStats stat : mCurrentStats) { + updateStats(stat, name, + mCurrentStats[UsageStatsManager.DAILY_BUCKET].mBeginTimeStamp, + UsageStats.Event.CONTINUE_PREVIOUS_DAY); + mStatsChanged = true; + } + } + persistActiveStats(); + + final long totalTime = System.currentTimeMillis() - startTime; + Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime + + " milliseconds"); + } + + private void notifyStatsChanged() { + if (!mStatsChanged) { + mStatsChanged = true; + mListener.onStatsUpdated(); + } + } + + private void loadActiveStats() { + final long timeNow = System.currentTimeMillis(); + + Calendar tempCal = mDailyExpiryDate; + for (int i = 0; i < mCurrentStats.length; i++) { + tempCal.setTimeInMillis(timeNow); + UsageStatsUtils.truncateDateTo(i, tempCal); + + if (mCurrentStats[i] != null && + mCurrentStats[i].mBeginTimeStamp == tempCal.getTimeInMillis()) { + // These are the same, no need to load them (in memory stats are always newer + // than persisted stats). + continue; + } + + UsageStats[] stats = mDatabase.getUsageStats(i, timeNow, 1); + if (stats != null && stats.length > 0) { + mCurrentStats[i] = stats[stats.length - 1]; + } else { + mCurrentStats[i] = UsageStats.create(tempCal.getTimeInMillis(), timeNow); + } + } + mStatsChanged = false; + mDailyExpiryDate.setTimeInMillis(timeNow); + mDailyExpiryDate.add(Calendar.DAY_OF_YEAR, 1); + UsageStatsUtils.truncateDateTo(UsageStatsManager.DAILY_BUCKET, mDailyExpiryDate); + Slog.i(TAG, mLogPrefix + "Rollover scheduled for " + + sDateFormat.format(mDailyExpiryDate.getTime())); + } + + private void updateStats(UsageStats stats, String packageName, long timeStamp, + int eventType) { + PackageUsageStats pkgStats = stats.getOrCreatePackageUsageStats(packageName); + + // TODO(adamlesinski): Ensure that we recover from incorrect event sequences + // like double MOVE_TO_BACKGROUND, etc. + if (eventType == UsageStats.Event.MOVE_TO_BACKGROUND || + eventType == UsageStats.Event.END_OF_DAY) { + if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND || + pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) { + pkgStats.mTotalTimeSpent += timeStamp - pkgStats.mLastTimeUsed; + } + } + pkgStats.mLastEvent = eventType; + pkgStats.mLastTimeUsed = timeStamp; + stats.mEndTimeStamp = timeStamp; + } + + private static String eventToString(int eventType) { + switch (eventType) { + case UsageStats.Event.NONE: + return "NONE"; + case UsageStats.Event.MOVE_TO_BACKGROUND: + return "MOVE_TO_BACKGROUND"; + case UsageStats.Event.MOVE_TO_FOREGROUND: + return "MOVE_TO_FOREGROUND"; + case UsageStats.Event.END_OF_DAY: + return "END_OF_DAY"; + case UsageStats.Event.CONTINUE_PREVIOUS_DAY: + return "CONTINUE_PREVIOUS_DAY"; + default: + return "UNKNOWN"; + } + } +} diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java index 1e0d6de7bc90..8913eb958fa7 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java @@ -28,8 +28,6 @@ import android.os.UserManager; import android.text.TextUtils; import android.util.Slog; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; /** @@ -39,43 +37,35 @@ import java.util.UUID; */ public class DatabaseHelper extends SQLiteOpenHelper { static final String TAG = "SoundModelDBHelper"; - static final boolean DBG = false; + // TODO: Set to false. + static final boolean DBG = true; private static final String NAME = "sound_model.db"; - private static final int VERSION = 2; - - public static interface KeyphraseContract { - public static final String TABLE = "keyphrase"; - public static final String KEY_ID = "_id"; - public static final String KEY_RECOGNITION_MODES = "modes"; - public static final String KEY_LOCALE = "locale"; - public static final String KEY_HINT_TEXT = "hint_text"; - public static final String KEY_USERS = "users"; - public static final String KEY_SOUND_MODEL_ID = "sound_model_id"; - } + private static final int VERSION = 3; public static interface SoundModelContract { public static final String TABLE = "sound_model"; - public static final String KEY_ID = "_id"; + public static final String KEY_KEYPHRASE_ID = "keyphrase_id"; + public static final String KEY_MODEL_UUID = "model_uuid"; public static final String KEY_TYPE = "type"; public static final String KEY_DATA = "data"; + public static final String KEY_RECOGNITION_MODES = "recognition_modes"; + public static final String KEY_LOCALE = "locale"; + public static final String KEY_HINT_TEXT = "hint_text"; + public static final String KEY_USERS = "users"; } - // Table Create Statements - private static final String CREATE_TABLE_KEYPRHASES = "CREATE TABLE " - + KeyphraseContract.TABLE + "(" - + KeyphraseContract.KEY_ID + " INTEGER PRIMARY KEY," - + KeyphraseContract.KEY_RECOGNITION_MODES + " INTEGER," - + KeyphraseContract.KEY_USERS + " TEXT," - + KeyphraseContract.KEY_SOUND_MODEL_ID + " TEXT," - + KeyphraseContract.KEY_LOCALE + " TEXT," - + KeyphraseContract.KEY_HINT_TEXT + " TEXT" + ")"; - + // Table Create Statement private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE " + SoundModelContract.TABLE + "(" - + SoundModelContract.KEY_ID + " TEXT PRIMARY KEY," + + SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER PRIMARY KEY," + + SoundModelContract.KEY_MODEL_UUID + " TEXT," + SoundModelContract.KEY_TYPE + " INTEGER," - + SoundModelContract.KEY_DATA + " BLOB" + ")"; + + SoundModelContract.KEY_DATA + " BLOB," + + SoundModelContract.KEY_RECOGNITION_MODES + " INTEGER," + + SoundModelContract.KEY_LOCALE + " TEXT," + + SoundModelContract.KEY_HINT_TEXT + " TEXT," + + SoundModelContract.KEY_USERS + " TEXT" + ")"; private final UserManager mUserManager; @@ -87,57 +77,44 @@ public class DatabaseHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { // creating required tables - db.execSQL(CREATE_TABLE_KEYPRHASES); db.execSQL(CREATE_TABLE_SOUND_MODEL); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO: For now, drop older tables and recreate new ones. - db.execSQL("DROP TABLE IF EXISTS " + KeyphraseContract.TABLE); db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE); onCreate(db); } - public boolean addOrUpdateKeyphraseSoundModel(KeyphraseSoundModel soundModel) { + /** + * Updates the given keyphrase model, adds it, if it doesn't already exist. + * + * TODO: We only support one keyphrase currently. + */ + public boolean updateKeyphraseSoundModel(KeyphraseSoundModel soundModel) { synchronized(this) { SQLiteDatabase db = getWritableDatabase(); ContentValues values = new ContentValues(); - // Generate a random ID for the model. - values.put(SoundModelContract.KEY_ID, soundModel.uuid.toString()); - values.put(SoundModelContract.KEY_DATA, soundModel.data); + values.put(SoundModelContract.KEY_MODEL_UUID, soundModel.uuid.toString()); values.put(SoundModelContract.KEY_TYPE, SoundTrigger.SoundModel.TYPE_KEYPHRASE); - - boolean status = true; - if (db.insertWithOnConflict(SoundModelContract.TABLE, null, values, - SQLiteDatabase.CONFLICT_REPLACE) != -1) { - for (Keyphrase keyphrase : soundModel.keyphrases) { - status &= addOrUpdateKeyphraseLocked(db, soundModel.uuid, keyphrase); + values.put(SoundModelContract.KEY_DATA, soundModel.data); + + if (soundModel.keyphrases != null && soundModel.keyphrases.length == 1) { + values.put(SoundModelContract.KEY_KEYPHRASE_ID, soundModel.keyphrases[0].id); + values.put(SoundModelContract.KEY_RECOGNITION_MODES, + soundModel.keyphrases[0].recognitionModes); + values.put(SoundModelContract.KEY_USERS, + getCommaSeparatedString(soundModel.keyphrases[0].users)); + values.put(SoundModelContract.KEY_LOCALE, soundModel.keyphrases[0].locale); + values.put(SoundModelContract.KEY_HINT_TEXT, soundModel.keyphrases[0].text); + try { + return db.insertWithOnConflict(SoundModelContract.TABLE, null, values, + SQLiteDatabase.CONFLICT_REPLACE) != -1; + } finally { + db.close(); } - db.close(); - return status; - } else { - Slog.w(TAG, "Failed to persist sound model to database"); - db.close(); - return false; } - } - } - - private boolean addOrUpdateKeyphraseLocked( - SQLiteDatabase db, UUID modelId, Keyphrase keyphrase) { - ContentValues values = new ContentValues(); - values.put(KeyphraseContract.KEY_ID, keyphrase.id); - values.put(KeyphraseContract.KEY_RECOGNITION_MODES, keyphrase.recognitionModes); - values.put(KeyphraseContract.KEY_SOUND_MODEL_ID, modelId.toString()); - values.put(KeyphraseContract.KEY_HINT_TEXT, keyphrase.text); - values.put(KeyphraseContract.KEY_LOCALE, keyphrase.locale); - values.put(KeyphraseContract.KEY_USERS, getCommaSeparatedString(keyphrase.users)); - if (db.insertWithOnConflict( - KeyphraseContract.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE) != -1) { - return true; - } else { - Slog.w(TAG, "Failed to persist keyphrase to database"); return false; } } @@ -145,111 +122,90 @@ public class DatabaseHelper extends SQLiteOpenHelper { /** * Deletes the sound model and associated keyphrases. */ - public boolean deleteKeyphraseSoundModel(UUID uuid) { + public boolean deleteKeyphraseSoundModel(int keyphraseId) { synchronized(this) { SQLiteDatabase db = getWritableDatabase(); - String modelId = uuid.toString(); - String soundModelClause = SoundModelContract.KEY_ID + "=" + modelId; - boolean status = true; - if (db.delete(SoundModelContract.TABLE, soundModelClause, null) == 0) { - Slog.w(TAG, "No sound models deleted from the database"); - status = false; - } - String keyphraseClause = KeyphraseContract.KEY_SOUND_MODEL_ID + "=" + modelId; - if (db.delete(KeyphraseContract.TABLE, keyphraseClause, null) == 0) { - Slog.w(TAG, "No keyphrases deleted from the database"); - status = false; + String soundModelClause = SoundModelContract.KEY_KEYPHRASE_ID + "=" + keyphraseId; + + try { + return db.delete(SoundModelContract.TABLE, soundModelClause, null) != 0; + } finally { + db.close(); } - db.close(); - return status; } } /** - * Lists all the keyphrase sound models currently registered with the system. + * Returns a matching {@link KeyphraseSoundModel} for the keyphrase ID. + * Returns null if a match isn't found. + * + * TODO: We only support one keyphrase currently. */ - public List<KeyphraseSoundModel> getKephraseSoundModels() { + public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId) { synchronized(this) { - List<KeyphraseSoundModel> models = new ArrayList<>(); - String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE; + // Find the corresponding sound model ID for the keyphrase. + String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE + + " WHERE " + SoundModelContract.KEY_KEYPHRASE_ID + " = '" + keyphraseId + "'"; SQLiteDatabase db = getReadableDatabase(); Cursor c = db.rawQuery(selectQuery, null); - - // looping through all rows and adding to list - if (c.moveToFirst()) { - do { + + try { + if (c.moveToFirst()) { int type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE)); if (type != SoundTrigger.SoundModel.TYPE_KEYPHRASE) { - // Ignore non-keyphrase sound models. - continue; + Slog.w(TAG, "No KeyphraseSoundModel available for the given keyphrase"); + return null; } - String id = c.getString(c.getColumnIndex(SoundModelContract.KEY_ID)); - byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA)); - // Get all the keyphrases for this this sound model. - // Validate the sound model. - if (id == null) { + + String modelUuid = c.getString( + c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID)); + if (modelUuid == null) { Slog.w(TAG, "Ignoring sound model since it doesn't specify an ID"); - continue; - } - KeyphraseSoundModel model = new KeyphraseSoundModel( - UUID.fromString(id), data, getKeyphrasesForSoundModelLocked(db, id)); - if (DBG) { - Slog.d(TAG, "Adding model: " + model); + return null; } - models.add(model); - } while (c.moveToNext()); - } - c.close(); - db.close(); - return models; - } - } - - private Keyphrase[] getKeyphrasesForSoundModelLocked(SQLiteDatabase db, String modelId) { - List<Keyphrase> keyphrases = new ArrayList<>(); - String selectQuery = "SELECT * FROM " + KeyphraseContract.TABLE - + " WHERE " + KeyphraseContract.KEY_SOUND_MODEL_ID + " = '" + modelId + "'"; - Cursor c = db.rawQuery(selectQuery, null); - // looping through all rows and adding to list - if (c.moveToFirst()) { - do { - int id = c.getInt(c.getColumnIndex(KeyphraseContract.KEY_ID)); - int modes = c.getInt(c.getColumnIndex(KeyphraseContract.KEY_RECOGNITION_MODES)); - int[] users = getArrayForCommaSeparatedString( - c.getString(c.getColumnIndex(KeyphraseContract.KEY_USERS))); - String locale = c.getString(c.getColumnIndex(KeyphraseContract.KEY_LOCALE)); - String hintText = c.getString(c.getColumnIndex(KeyphraseContract.KEY_HINT_TEXT)); - - // Only add keyphrases meant for the current user. - if (users == null) { - // No users present in the keyphrase. - Slog.w(TAG, "Ignoring keyphrase since it doesn't specify users"); - continue; - } - boolean isAvailableForCurrentUser = false; - int currentUser = mUserManager.getUserHandle(); - for (int user : users) { - if (currentUser == user) { - isAvailableForCurrentUser = true; - break; + byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA)); + int recognitionModes = c.getInt( + c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES)); + int[] users = getArrayForCommaSeparatedString( + c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS))); + String locale = c.getString(c.getColumnIndex(SoundModelContract.KEY_LOCALE)); + String text = c.getString( + c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT)); + + // Only add keyphrases meant for the current user. + if (users == null) { + // No users present in the keyphrase. + Slog.w(TAG, "Ignoring keyphrase since it doesn't specify users"); + return null; + } + boolean isAvailableForCurrentUser = false; + int currentUser = mUserManager.getUserHandle(); + for (int user : users) { + if (currentUser == user) { + isAvailableForCurrentUser = true; + break; + } + } + if (!isAvailableForCurrentUser) { + Slog.w(TAG, "Ignoring keyphrase since it's not for the current user"); + return null; } - } - if (!isAvailableForCurrentUser) { - Slog.w(TAG, "Ignoring keyphrase since it's not for the current user"); - continue; - } - keyphrases.add(new Keyphrase(id, modes, locale, hintText, users)); - } while (c.moveToNext()); + Keyphrase[] keyphrases = new Keyphrase[1]; + keyphrases[0] = new Keyphrase( + keyphraseId, recognitionModes, locale, text, users); + return new KeyphraseSoundModel(UUID.fromString(modelUuid), data, keyphrases); + } + Slog.w(TAG, "No SoundModel available for the given keyphrase"); + } finally { + c.close(); + db.close(); + } + return null; } - Keyphrase[] keyphraseArr = new Keyphrase[keyphrases.size()]; - keyphrases.toArray(keyphraseArr); - c.close(); - return keyphraseArr; } - private static String getCommaSeparatedString(int[] users) { if (users == null || users.length == 0) { return ""; diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java index 4430586e083a..1e4a518c1c16 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java @@ -38,7 +38,8 @@ import java.util.ArrayList; */ public class SoundTriggerHelper implements SoundTrigger.StatusListener { static final String TAG = "SoundTriggerHelper"; - static final boolean DBG = false; + // TODO: Set to false. + static final boolean DBG = true; // TODO: Remove this. static final int TEMP_KEYPHRASE_ID = 100; @@ -237,20 +238,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { switch (event.status) { case SoundTrigger.RECOGNITION_STATUS_SUCCESS: - // TODO: Pass the captured audio back. try { - listener.onDetected(null); + listener.onDetected(event); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in onDetected"); } break; - case SoundTrigger.RECOGNITION_STATUS_ABORT: - try { - listener.onDetectionStopped(); - } catch (RemoteException e) { - Slog.w(TAG, "RemoteException in onDetectionStopped"); - } - break; + case SoundTrigger.RECOGNITION_STATUS_ABORT: // fall-through case SoundTrigger.RECOGNITION_STATUS_FAILURE: try { listener.onDetectionStopped(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 5d9e1072f4bc..a3d578a5dbb9 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -50,6 +50,7 @@ import com.android.server.UiThread; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.List; +import java.util.UUID; /** @@ -243,34 +244,18 @@ public class VoiceInteractionManagerService extends SystemService { //----------------- Model management APIs --------------------------------// @Override - public List<KeyphraseSoundModel> listRegisteredKeyphraseSoundModels( - IVoiceInteractionService service) { - // Allow the call if this is the current voice interaction service - // or the caller holds the MANAGE_VOICE_KEYPHRASES permission. + public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId) { synchronized (this) { - boolean permissionGranted = - mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) - == PackageManager.PERMISSION_GRANTED; - boolean currentVoiceInteractionService = service != null - && mImpl != null - && mImpl.mService != null - && service.asBinder() == mImpl.mService.asBinder(); - - if (!permissionGranted && !currentVoiceInteractionService) { - if (!currentVoiceInteractionService) { - throw new SecurityException( - "Caller is not the current voice interaction service"); - } - if (!permissionGranted) { - throw new SecurityException("Caller does not hold the permission " - + Manifest.permission.MANAGE_VOICE_KEYPHRASES); - } + if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Caller does not hold the permission " + + Manifest.permission.MANAGE_VOICE_KEYPHRASES); } } final long caller = Binder.clearCallingIdentity(); try { - return mDbHelper.getKephraseSoundModels(); + return mDbHelper.getKeyphraseSoundModel(keyphraseId); } finally { Binder.restoreCallingIdentity(caller); } @@ -291,15 +276,35 @@ public class VoiceInteractionManagerService extends SystemService { final long caller = Binder.clearCallingIdentity(); try { - boolean success = false; - if (model.keyphrases == null) { - // If the keyphrases are not present in the model, delete the model. - success = mDbHelper.deleteKeyphraseSoundModel(model.uuid); + if (mDbHelper.updateKeyphraseSoundModel(model)) { + synchronized (this) { + // Notify the voice interaction service of a change in sound models. + if (mImpl != null && mImpl.mService != null) { + mImpl.notifySoundModelsChangedLocked(); + } + } + return SoundTriggerHelper.STATUS_OK; } else { - // Else update the model. - success = mDbHelper.addOrUpdateKeyphraseSoundModel(model); + return SoundTriggerHelper.STATUS_ERROR; } - if (success) { + } finally { + Binder.restoreCallingIdentity(caller); + } + } + + @Override + public int deleteKeyphraseSoundModel(int keyphraseId) { + synchronized (this) { + if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Caller does not hold the permission " + + Manifest.permission.MANAGE_VOICE_KEYPHRASES); + } + } + + final long caller = Binder.clearCallingIdentity(); + try { + if (mDbHelper.deleteKeyphraseSoundModel(keyphraseId)) { synchronized (this) { // Notify the voice interaction service of a change in sound models. if (mImpl != null && mImpl.mService != null) { @@ -317,6 +322,25 @@ public class VoiceInteractionManagerService extends SystemService { //----------------- SoundTrigger APIs --------------------------------// @Override + public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId) { + synchronized (this) { + if (mImpl == null || mImpl.mService == null + || service.asBinder() != mImpl.mService.asBinder()) { + throw new SecurityException( + "Caller is not the current voice interaction service"); + } + } + + final long caller = Binder.clearCallingIdentity(); + try { + KeyphraseSoundModel model = mDbHelper.getKeyphraseSoundModel(keyphraseId); + return model != null; + } finally { + Binder.restoreCallingIdentity(caller); + } + } + + @Override public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) { // Allow the call if this is the current voice interaction service. synchronized (this) { @@ -337,8 +361,7 @@ public class VoiceInteractionManagerService extends SystemService { @Override public int startRecognition(IVoiceInteractionService service, int keyphraseId, - KeyphraseSoundModel soundModel, IRecognitionStatusCallback callback, - RecognitionConfig recognitionConfig) { + IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) { // Allow the call if this is the current voice interaction service. synchronized (this) { if (mImpl == null || mImpl.mService == null @@ -347,13 +370,25 @@ public class VoiceInteractionManagerService extends SystemService { "Caller is not the current voice interaction service"); } - final long caller = Binder.clearCallingIdentity(); - try { + if (callback == null || recognitionConfig == null) { + throw new IllegalArgumentException("Illegal argument(s) in startRecognition"); + } + } + + final long caller = Binder.clearCallingIdentity(); + try { + KeyphraseSoundModel soundModel = mDbHelper.getKeyphraseSoundModel(keyphraseId); + if (soundModel == null + || soundModel.uuid == null + || soundModel.keyphrases == null) { + Slog.w(TAG, "No matching sound model found in startRecognition"); + return SoundTriggerHelper.STATUS_ERROR; + } else { return mSoundTriggerHelper.startRecognition( keyphraseId, soundModel, callback, recognitionConfig); - } finally { - Binder.restoreCallingIdentity(caller); } + } finally { + Binder.restoreCallingIdentity(caller); } } @@ -367,13 +402,13 @@ public class VoiceInteractionManagerService extends SystemService { throw new SecurityException( "Caller is not the current voice interaction service"); } + } - final long caller = Binder.clearCallingIdentity(); - try { - return mSoundTriggerHelper.stopRecognition(keyphraseId, callback); - } finally { - Binder.restoreCallingIdentity(caller); - } + final long caller = Binder.clearCallingIdentity(); + try { + return mSoundTriggerHelper.stopRecognition(keyphraseId, callback); + } finally { + Binder.restoreCallingIdentity(caller); } } diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java index ad5c614c6acf..838f221400a7 100644 --- a/telecomm/java/android/telecomm/Call.java +++ b/telecomm/java/android/telecomm/Call.java @@ -18,9 +18,9 @@ package android.telecomm; import android.app.PendingIntent; import android.net.Uri; -import android.os.RemoteException; import android.telephony.DisconnectCause; +import java.lang.String; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -309,15 +309,13 @@ public final class Call { public void onPostDialWait(Call call, String remainingPostDialSequence) {} /** - * Invoked when the {@code RemoteCallVideoProvider} of the {@code Call} has changed. + * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed. * * @param call The {@code Call} invoking this method. - * @param callVideoProvider The {@code RemoteCallVideoProvider} associated with the - * {@code Call}. + * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}. */ - public void onCallVideoProviderChanged(Call call, - RemoteCallVideoProvider callVideoProvider) {} + public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {} /** * Launches an activity for this connection on top of the in-call UI. @@ -348,7 +346,7 @@ public final class Call { private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren); private List<String> mCannedTextResponses = null; private String mRemainingPostDialSequence; - private RemoteCallVideoProvider mCallVideoProvider; + private InCallService.VideoCall mVideoCall; private Details mDetails; private final List<Listener> mListeners = new ArrayList<>(); @@ -533,10 +531,10 @@ public final class Call { /** * Obtains an object that can be used to display video from this {@code Call}. * - * @return An {@code ICallVideoProvider}. + * @return An {@code Call.VideoCall}. */ - public RemoteCallVideoProvider getCallVideoProvider() { - return mCallVideoProvider; + public InCallService.VideoCall getVideoCall() { + return mVideoCall; } /** @@ -609,14 +607,9 @@ public final class Call { Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); } - boolean callVideoProviderChanged = false; - try { - callVideoProviderChanged = - !Objects.equals(mCallVideoProvider, parcelableCall.getCallVideoProvider()); - if (callVideoProviderChanged) { - mCallVideoProvider = parcelableCall.getCallVideoProvider(); - } - } catch (RemoteException e) { + boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall()); + if (videoCallChanged) { + mVideoCall = parcelableCall.getVideoCall(); } int state = stateFromParcelableCallState(parcelableCall.getState()); @@ -649,8 +642,8 @@ public final class Call { if (cannedTextResponsesChanged) { fireCannedTextResponsesLoaded(mCannedTextResponses); } - if (callVideoProviderChanged) { - fireCallVideoProviderChanged(mCallVideoProvider); + if (videoCallChanged) { + fireVideoCallChanged(mVideoCall); } // If we have transitioned to DISCONNECTED, that means we need to notify clients and @@ -715,10 +708,10 @@ public final class Call { } } - private void fireCallVideoProviderChanged(RemoteCallVideoProvider callVideoProvider) { + private void fireVideoCallChanged(InCallService.VideoCall videoCall) { Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]); for (int i = 0; i < listeners.length; i++) { - listeners[i].onCallVideoProviderChanged(this, callVideoProvider); + listeners[i].onVideoCallChanged(this, videoCall); } } @@ -773,4 +766,4 @@ public final class Call { return STATE_NEW; } } -} +}
\ No newline at end of file diff --git a/telecomm/java/android/telecomm/CallVideoClient.java b/telecomm/java/android/telecomm/CallVideoClient.java deleted file mode 100644 index 00473ffd3cb6..000000000000 --- a/telecomm/java/android/telecomm/CallVideoClient.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * 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 android.telecomm; - -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; - -import com.android.internal.os.SomeArgs; -import com.android.internal.telecomm.ICallVideoClient; - -/** - * Base implementation of a CallVideoClient which communicates changes to video properties of a call - * from the framework to the current InCall-UI. - */ -public abstract class CallVideoClient { - - /** - * Video is not being received (no protocol pause was issued). - */ - public static final int SESSION_EVENT_RX_PAUSE = 1; - - /** - * Video reception has resumed after a SESSION_EVENT_RX_PAUSE. - */ - public static final int SESSION_EVENT_RX_RESUME = 2; - - /** - * Video transmission has begun. This occurs after a negotiated start of video transmission - * when the underlying protocol has actually begun transmitting video to the remote party. - */ - public static final int SESSION_EVENT_TX_START = 3; - - /** - * Video transmission has stopped. This occur after a negotiated stop of video transmission when - * the underlying protocol has actually stopped transmitting video to the remote party. - */ - public static final int SESSION_EVENT_TX_STOP = 4; - - /** - * Session modify request was successful. - */ - public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; - - /** - * Session modify request failed. - */ - public static final int SESSION_MODIFY_REQUEST_FAIL = 2; - - /** - * Session modify request ignored due to invalid parameters. - */ - public static final int SESSION_MODIFY_REQUEST_INVALID = 3; - - private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1; - private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2; - private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3; - private static final int MSG_UPDATE_PEER_DIMENSIONS = 4; - private static final int MSG_UPDATE_CALL_DATA_USAGE = 5; - private static final int MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE = 6; - - /** Default Handler used to consolidate binder method calls onto a single thread. */ - private final Handler mHandler = new Handler(Looper.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_RECEIVE_SESSION_MODIFY_REQUEST: - onReceiveSessionModifyRequest((VideoCallProfile) msg.obj); - break; - case MSG_RECEIVE_SESSION_MODIFY_RESPONSE: { - SomeArgs args = (SomeArgs) msg.obj; - try { - int status = (int) args.arg1; - VideoCallProfile requestProfile = (VideoCallProfile) args.arg2; - VideoCallProfile responseProfile = (VideoCallProfile) args.arg3; - - onReceiveSessionModifyResponse(status, requestProfile, - responseProfile); - } finally { - args.recycle(); - } - break; - } - case MSG_HANDLE_CALL_SESSION_EVENT: - onHandleCallSessionEvent((int) msg.obj); - break; - case MSG_UPDATE_PEER_DIMENSIONS: { - SomeArgs args = (SomeArgs) msg.obj; - try { - int width = (int) args.arg1; - int height = (int) args.arg2; - onUpdatePeerDimensions(width, height); - } finally { - args.recycle(); - } - break; - } - case MSG_UPDATE_CALL_DATA_USAGE: - onUpdateCallDataUsage(msg.arg1); - break; - case MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE: - onHandleCameraCapabilitiesChange((CallCameraCapabilities) msg.obj); - break; - default: - break; - } - } - }; - - /** - * Default ICallVideoClient implementation. - */ - private final class CallVideoClientBinder extends ICallVideoClient.Stub { - @Override - public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) { - mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST, - videoCallProfile).sendToTarget(); - } - - @Override - public void receiveSessionModifyResponse(int status, - VideoCallProfile requestProfile, VideoCallProfile responseProfile) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = status; - args.arg2 = requestProfile; - args.arg3 = responseProfile; - mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget(); - } - - @Override - public void handleCallSessionEvent(int event) { - mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget(); - } - - @Override - public void updatePeerDimensions(int width, int height) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = width; - args.arg2 = height; - mHandler.obtainMessage(MSG_UPDATE_PEER_DIMENSIONS, args).sendToTarget(); - } - - @Override - public void updateCallDataUsage(int dataUsage) { - mHandler.obtainMessage(MSG_UPDATE_CALL_DATA_USAGE, dataUsage).sendToTarget(); - } - - @Override - public void handleCameraCapabilitiesChange(CallCameraCapabilities cameraCapabilities) { - mHandler.obtainMessage(MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE, - cameraCapabilities).sendToTarget(); - } - } - - private final CallVideoClientBinder mBinder; - - public CallVideoClient() { - mBinder = new CallVideoClientBinder(); - } - - /** - * Returns binder object which can be used across IPC methods. - * @hide - */ - public final IBinder getBinder() { - return mBinder; - } - - /** - * Called when a session modification request is received from the remote device. - * The remote request is sent via {@link CallVideoProvider#onSendSessionModifyRequest}. - * The InCall UI is responsible for potentially prompting the user whether they wish to accept - * the new call profile (e.g. prompt user if they wish to accept an upgrade from an audio to a - * video call) and should call {@link CallVideoProvider#onSendSessionModifyResponse} to indicate - * the video settings the user has agreed to. - * - * @param videoCallProfile The requested video call profile. - */ - public abstract void onReceiveSessionModifyRequest(VideoCallProfile videoCallProfile); - - /** - * Called when a response to a session modification request is received from the remote device. - * The remote InCall UI sends the response using - * {@link CallVideoProvider#onSendSessionModifyResponse}. - * - * @param status Status of the session modify request. Valid values are - * {@link CallVideoClient#SESSION_MODIFY_REQUEST_SUCCESS}, - * {@link CallVideoClient#SESSION_MODIFY_REQUEST_FAIL}, - * {@link CallVideoClient#SESSION_MODIFY_REQUEST_INVALID} - * @param requestProfile The original request which was sent to the remote device. - * @param responseProfile The actual profile changes made by the remote device. - */ - public abstract void onReceiveSessionModifyResponse(int status, - VideoCallProfile requestProfile, VideoCallProfile responseProfile); - - /** - * Handles events related to the current session which the client may wish to handle. These - * are separate from requested changes to the session due to the underlying protocol or - * connection. - * Valid values are: {@link CallVideoClient#SESSION_EVENT_RX_PAUSE}, - * {@link CallVideoClient#SESSION_EVENT_RX_RESUME}, - * {@link CallVideoClient#SESSION_EVENT_TX_START}, {@link CallVideoClient#SESSION_EVENT_TX_STOP} - * - * @param event The event. - */ - public abstract void onHandleCallSessionEvent(int event); - - /** - * Handles a change to the video dimensions from the remote caller (peer). This could happen - * if, for example, the peer changes orientation of their device. - * - * @param width The updated peer video width. - * @param height The updated peer video height. - */ - public abstract void onUpdatePeerDimensions(int width, int height); - - /** - * Handles an update to the total data used for the current session. - * - * @param dataUsage The updated data usage. - */ - public abstract void onUpdateCallDataUsage(int dataUsage); - - /** - * Handles a change in camera capabilities. - * - * @param callCameraCapabilities The changed camera capabilities. - */ - public abstract void onHandleCameraCapabilitiesChange( - CallCameraCapabilities callCameraCapabilities); -} - diff --git a/telecomm/java/android/telecomm/CallVideoProvider.java b/telecomm/java/android/telecomm/CallVideoProvider.java deleted file mode 100644 index 443a5b6b5c6d..000000000000 --- a/telecomm/java/android/telecomm/CallVideoProvider.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 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 android.telecomm; - -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.RemoteException; -import android.view.Surface; - -import com.android.internal.telecomm.ICallVideoClient; -import com.android.internal.telecomm.ICallVideoProvider; - -public abstract class CallVideoProvider { - private static final int MSG_SET_CALL_VIDEO_CLIENT = 1; - private static final int MSG_SET_CAMERA = 2; - private static final int MSG_SET_PREVIEW_SURFACE = 3; - private static final int MSG_SET_DISPLAY_SURFACE = 4; - private static final int MSG_SET_DEVICE_ORIENTATION = 5; - private static final int MSG_SET_ZOOM = 6; - private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7; - private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8; - private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; - private static final int MSG_REQUEST_CALL_DATA_USAGE = 10; - private static final int MSG_SET_PAUSE_IMAGE = 11; - - /** - * Default handler used to consolidate binder method calls onto a single thread. - */ - private final class CallVideoProviderHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_SET_CALL_VIDEO_CLIENT: - try { - ICallVideoClient callVideoClient = - ICallVideoClient.Stub.asInterface((IBinder) msg.obj); - RemoteCallVideoClient remoteCallVideoClient = - new RemoteCallVideoClient(callVideoClient); - onSetCallVideoClient(remoteCallVideoClient); - } catch (RemoteException ignored) { - } - break; - case MSG_SET_CAMERA: - onSetCamera((String) msg.obj); - break; - case MSG_SET_PREVIEW_SURFACE: - onSetPreviewSurface((Surface) msg.obj); - break; - case MSG_SET_DISPLAY_SURFACE: - onSetDisplaySurface((Surface) msg.obj); - break; - case MSG_SET_DEVICE_ORIENTATION: - onSetDeviceOrientation(msg.arg1); - break; - case MSG_SET_ZOOM: - onSetZoom((Float) msg.obj); - break; - case MSG_SEND_SESSION_MODIFY_REQUEST: - onSendSessionModifyRequest((VideoCallProfile) msg.obj); - break; - case MSG_SEND_SESSION_MODIFY_RESPONSE: - onSendSessionModifyResponse((VideoCallProfile) msg.obj); - break; - case MSG_REQUEST_CAMERA_CAPABILITIES: - onRequestCameraCapabilities(); - break; - case MSG_REQUEST_CALL_DATA_USAGE: - onRequestCallDataUsage(); - break; - case MSG_SET_PAUSE_IMAGE: - onSetPauseImage((String) msg.obj); - break; - default: - break; - } - } - } - - /** - * Default ICallVideoProvider implementation. - */ - private final class CallVideoProviderBinder extends ICallVideoProvider.Stub { - public void setCallVideoClient(IBinder callVideoClientBinder) { - mMessageHandler.obtainMessage( - MSG_SET_CALL_VIDEO_CLIENT, callVideoClientBinder).sendToTarget(); - } - - public void setCamera(String cameraId) { - mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget(); - } - - public void setPreviewSurface(Surface surface) { - mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget(); - } - - public void setDisplaySurface(Surface surface) { - mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget(); - } - - public void setDeviceOrientation(int rotation) { - mMessageHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation).sendToTarget(); - } - - public void setZoom(float value) { - mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget(); - } - - public void sendSessionModifyRequest(VideoCallProfile requestProfile) { - mMessageHandler.obtainMessage( - MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget(); - } - - public void sendSessionModifyResponse(VideoCallProfile responseProfile) { - mMessageHandler.obtainMessage( - MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget(); - } - - public void requestCameraCapabilities() { - mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget(); - } - - public void requestCallDataUsage() { - mMessageHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget(); - } - - public void setPauseImage(String uri) { - mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget(); - } - } - - private final CallVideoProviderHandler mMessageHandler = new CallVideoProviderHandler(); - private final CallVideoProviderBinder mBinder; - - public CallVideoProvider() { - mBinder = new CallVideoProviderBinder(); - } - - /** - * Returns binder object which can be used across IPC methods. - * @hide - */ - public final ICallVideoProvider getInterface() { - return mBinder; - } - - /** - * Sets a remote interface for invoking callback methods in the InCallUI after performing - * telephony actions. - * - * @param callVideoClient The call video client. - */ - public abstract void onSetCallVideoClient(RemoteCallVideoClient callVideoClient); - - /** - * Sets the camera to be used for video recording in a video call. - * - * @param cameraId The id of the camera. - */ - public abstract void onSetCamera(String cameraId); - - /** - * Sets the surface to be used for displaying a preview of what the user's camera is - * currently capturing. When video transmission is enabled, this is the video signal which is - * sent to the remote device. - * - * @param surface The surface. - */ - public abstract void onSetPreviewSurface(Surface surface); - - /** - * Sets the surface to be used for displaying the video received from the remote device. - * - * @param surface The surface. - */ - public abstract void onSetDisplaySurface(Surface surface); - - /** - * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of the - * device is 0 degrees. - * - * @param rotation The device orientation, in degrees. - */ - public abstract void onSetDeviceOrientation(int rotation); - - /** - * Sets camera zoom ratio. - * - * @param value The camera zoom ratio. - */ - public abstract void onSetZoom(float value); - - /** - * Issues a request to modify the properties of the current session. The request is sent to - * the remote device where it it handled by - * {@link CallVideoClient#onReceiveSessionModifyRequest}. - * Some examples of session modification requests: upgrade call from audio to video, downgrade - * call from video to audio, pause video. - * - * @param requestProfile The requested call video properties. - */ - public abstract void onSendSessionModifyRequest(VideoCallProfile requestProfile); - - /** - * Provides a response to a request to change the current call session video - * properties. - * This is in response to a request the InCall UI has received via - * {@link CallVideoClient#onReceiveSessionModifyRequest}. - * The response is handled on the remove device by - * {@link CallVideoClient#onReceiveSessionModifyResponse}. - * - * @param responseProfile The response call video properties. - */ - public abstract void onSendSessionModifyResponse(VideoCallProfile responseProfile); - - /** - * Issues a request to the video provider to retrieve the camera capabilities. - * Camera capabilities are reported back to the caller via - * {@link CallVideoClient#onHandleCameraCapabilitiesChange(CallCameraCapabilities)}. - */ - public abstract void onRequestCameraCapabilities(); - - /** - * Issues a request to the video telephony framework to retrieve the cumulative data usage for - * the current call. Data usage is reported back to the caller via - * {@link CallVideoClient#onUpdateCallDataUsage}. - */ - public abstract void onRequestCallDataUsage(); - - /** - * Provides the video telephony framework with the URI of an image to be displayed to remote - * devices when the video signal is paused. - * - * @param uri URI of image to display. - */ - public abstract void onSetPauseImage(String uri); -} diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java index 02af68edfe13..322dafee639e 100644 --- a/telecomm/java/android/telecomm/Connection.java +++ b/telecomm/java/android/telecomm/Connection.java @@ -19,10 +19,8 @@ package android.telecomm; import android.app.PendingIntent; import android.net.Uri; import android.os.Bundle; -import android.telecomm.CallVideoProvider; import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -46,21 +44,27 @@ public abstract class Connection { public void onDestroyed(Connection c) {} public void onCallCapabilitiesChanged(Connection c, int callCapabilities) {} public void onParentConnectionChanged(Connection c, Connection parent) {} - public void onCallVideoProviderChanged(Connection c, CallVideoProvider callVideoProvider) {} + public void onVideoCallProviderChanged( + Connection c, ConnectionService.VideoCallProvider videoCallProvider) {} public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {} public void onStatusHintsChanged(Connection c, StatusHints statusHints) {} public void onStartActivityFromInCall(Connection c, PendingIntent intent) {} + public void onFailed(Connection c, int code, String msg) {} } public final class State { private State() {} - public static final int NEW = 0; - public static final int RINGING = 1; - public static final int DIALING = 2; - public static final int ACTIVE = 3; - public static final int HOLDING = 4; - public static final int DISCONNECTED = 5; + public static final int INITIALIZING = 0; + public static final int NEW = 1; + public static final int RINGING = 2; + public static final int DIALING = 3; + public static final int ACTIVE = 4; + public static final int HOLDING = 5; + public static final int DISCONNECTED = 6; + public static final int FAILED = 7; + public static final int CANCELED = 8; + } private final Set<Listener> mListeners = new HashSet<>(); @@ -75,10 +79,13 @@ public abstract class Connection { private boolean mRequestingRingback = false; private int mCallCapabilities; private Connection mParentConnection; - private CallVideoProvider mCallVideoProvider; + private ConnectionService.VideoCallProvider mVideoCallProvider; private boolean mAudioModeIsVoip; private StatusHints mStatusHints; private int mVideoState; + private int mFailureCode; + private String mFailureMessage; + private boolean mIsCanceled; /** * Create a new Connection. @@ -199,6 +206,20 @@ public abstract class Connection { } /** + * @return The failure code ({@see DisconnectCause}) associated with this failed connection. + */ + public final int getFailureCode() { + return mFailureCode; + } + + /** + * @return The reason for the connection failure. This will not be displayed to the user. + */ + public final String getFailureMessage() { + return mFailureMessage; + } + + /** * Inform this Connection that the state of its audio output has been changed externally. * * @param state The new audio state. @@ -228,6 +249,10 @@ public abstract class Connection { return "HOLDING"; case State.DISCONNECTED: return "DISCONNECTED"; + case State.FAILED: + return "FAILED"; + case State.CANCELED: + return "CANCELED"; default: Log.wtf(Connection.class, "Unknown state %d", state); return "UNKNOWN"; @@ -302,6 +327,33 @@ public abstract class Connection { } /** + * Cancel the {@link Connection}. Once this is called, the {@link Connection} will not be used, + * and no subsequent {@link Connection}s will be attempted. + */ + public final void setCanceled() { + Log.d(this, "setCanceled"); + setState(State.CANCELED); + } + + /** + * Move the {@link Connection} to the {@link State#FAILED} state, with the given code + * ({@see DisconnectCause}) and message. This message is not shown to the user, but is useful + * for logging and debugging purposes. + * <p> + * After calling this, the {@link Connection} will not be used. + * + * @param code The {@link android.telephony.DisconnectCause} indicating why the connection + * failed. + * @param message A message explaining why the {@link Connection} failed. + */ + public final void setFailed(int code, String message) { + Log.d(this, "setFailed (%d: %s)", code, message); + mFailureCode = code; + mFailureMessage = message; + setState(State.FAILED); + } + + /** * Set the video state for the connection. * Valid values: {@link android.telecomm.VideoCallProfile#VIDEO_STATE_AUDIO_ONLY}, * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL}, @@ -335,6 +387,20 @@ public abstract class Connection { } /** + * Sets state to initializing (this Connection is not yet ready to be used). + */ + public final void setInitializing() { + setState(State.INITIALIZING); + } + + /** + * Sets state to initialized (the Connection has been set up and is now ready to be used). + */ + public final void setInitialized() { + setState(State.NEW); + } + + /** * Sets state to dialing (e.g., dialing an outbound call). */ public final void setDialing() { @@ -349,18 +415,18 @@ public abstract class Connection { } /** - * Sets the call video provider. - * @param callVideoProvider The call video provider. + * Sets the video call provider. + * @param videoCallProvider The video call provider. */ - public final void setCallVideoProvider(CallVideoProvider callVideoProvider) { - mCallVideoProvider = callVideoProvider; + public final void setVideoCallProvider(ConnectionService.VideoCallProvider videoCallProvider) { + mVideoCallProvider = videoCallProvider; for (Listener l : mListeners) { - l.onCallVideoProviderChanged(this, callVideoProvider); + l.onVideoCallProviderChanged(this, videoCallProvider); } } - public final CallVideoProvider getCallVideoProvider() { - return mCallVideoProvider; + public final ConnectionService.VideoCallProvider getVideoCallProvider() { + return mVideoCallProvider; } /** @@ -487,8 +553,8 @@ public abstract class Connection { public void onSetAudioState(CallAudioState state) {} /** - * Notifies this Connection of an internal state change. This method is called before the - * state is actually changed. + * Notifies this Connection of an internal state change. This method is called after the + * state is changed. * * @param state The new state, a {@link Connection.State} member. */ @@ -579,11 +645,50 @@ public abstract class Connection { } private void setState(int state) { - Log.d(this, "setState: %s", stateToString(state)); - this.mState = state; - for (Listener l : mListeners) { - l.onStateChanged(this, state); + if (mState == State.FAILED || mState == State.CANCELED) { + Log.d(this, "Connection already %s; cannot transition out of this state.", + stateToString(mState)); + return; } - onSetState(state); + if (mState != state) { + Log.d(this, "setState: %s", stateToString(state)); + mState = state; + for (Listener l : mListeners) { + l.onStateChanged(this, state); + } + onSetState(state); + } + } + + /** + * Return a {@link Connection} which represents a failed connection attempt. The returned + * {@link Connection} will have {@link #getFailureCode()}, {@link #getFailureMessage()}, and + * {@link #getState()} set appropriately, but the {@link Connection} itself should not be used + * for anything. + * + * @param code The failure code ({@see DisconnectCause}). + * @param message A reason for why the connection failed (not intended to be shown to the user). + * @return A {@link Connection} which indicates failure. + */ + public static Connection getFailedConnection(final int code, final String message) { + return new Connection() {{ + setFailed(code, message); + }}; + } + + private static final Connection CANCELED_CONNECTION = new Connection() {{ + setCanceled(); + }}; + + /** + * Return a {@link Connection} which represents a canceled a connection attempt. The returned + * {@link Connection} will have state {@link State#CANCELED}, and cannot be moved out of that + * state. This connection should not be used for anything, and no other {@link Connection}s + * should be attempted. + * + * @return A {@link Connection} which indicates that the underlying call should be canceled. + */ + public static Connection getCanceledConnection() { + return CANCELED_CONNECTION; } } diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java index 4d945a31f98a..020b692b8d59 100644 --- a/telecomm/java/android/telecomm/ConnectionRequest.java +++ b/telecomm/java/android/telecomm/ConnectionRequest.java @@ -20,6 +20,8 @@ import android.net.Uri; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.ResultReceiver; +import android.telephony.DisconnectCause; /** * Simple data container encapsulating a request to some entity to @@ -110,6 +112,7 @@ public final class ConnectionRequest implements Parcelable { return mVideoState; } + @Override public String toString() { return String.format("PhoneConnectionRequest %s %s", mHandle == null diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java index d5b39cf12cae..cefa92935b6c 100644 --- a/telecomm/java/android/telecomm/ConnectionService.java +++ b/telecomm/java/android/telecomm/ConnectionService.java @@ -28,10 +28,15 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.telephony.DisconnectCause; +import android.os.RemoteException; +import android.view.Surface; import com.android.internal.os.SomeArgs; import com.android.internal.telecomm.IConnectionService; import com.android.internal.telecomm.IConnectionServiceAdapter; +import com.android.internal.telecomm.IVideoCallCallback; +import com.android.internal.telecomm.IVideoCallProvider; import com.android.internal.telecomm.RemoteServiceCallback; import java.util.Collection; @@ -132,7 +137,7 @@ public abstract class ConnectionService extends Service { public void answer(String callId, int videoState) { SomeArgs args = SomeArgs.obtain(); args.arg1 = callId; - args.arg2 = videoState; + args.argi1 = videoState; mHandler.obtainMessage(MSG_ANSWER, args).sendToTarget(); } @@ -224,7 +229,7 @@ public abstract class ConnectionService extends Service { SomeArgs args = (SomeArgs) msg.obj; try { String callId = (String) args.arg1; - int videoState = (int) args.arg2; + int videoState = args.argi1; answer(callId, videoState); } finally { args.recycle(); @@ -390,9 +395,9 @@ public abstract class ConnectionService extends Service { } @Override - public void onCallVideoProviderChanged(Connection c, CallVideoProvider callVideoProvider) { + public void onVideoCallProviderChanged(Connection c, VideoCallProvider videoCallProvider) { String id = mIdByConnection.get(c); - mAdapter.setCallVideoProvider(id, callVideoProvider); + mAdapter.setVideoCallProvider(id, videoCallProvider); } @Override @@ -425,48 +430,76 @@ public abstract class ConnectionService extends Service { * incoming call. In either case, telecomm will cycle through a set of services and call * createConnection util a connection service cancels the process or completes it successfully. */ - private void createConnection(ConnectionRequest originalRequest, boolean isIncoming) { - Log.d(this, "call %s", originalRequest); - CreateConnectionResponse response = new CreateConnectionResponse<Connection>() { - @Override - public void onSuccess(ConnectionRequest request, Connection connection) { - Log.d(this, "adapter handleCreateConnectionSuccessful %s", - request.getCallId()); - addConnection(request.getCallId(), connection); - mAdapter.handleCreateConnectionSuccessful( - request, - new ParcelableConnection( - request.getAccountHandle(), - connection.getState(), - connection.getCallCapabilities(), - connection.getHandle(), - connection.getHandlePresentation(), - connection.getCallerDisplayName(), - connection.getCallerDisplayNamePresentation(), - connection.getCallVideoProvider() == null ? - null : connection.getCallVideoProvider().getInterface(), - connection.getVideoState())); - } + private void createConnection(final ConnectionRequest request, boolean isIncoming) { + Log.d(this, "call %s", request); - @Override - public void onFailure(ConnectionRequest request, int code, String msg) { - // Tell telecomm to try a different service. - mAdapter.handleCreateConnectionFailed(request, code, msg); - } + final Connection createdConnection; + if (isIncoming) { + createdConnection = onCreateIncomingConnection(request); + } else { + createdConnection = onCreateOutgoingConnection(request); + } - @Override - public void onCancel(ConnectionRequest request) { + if (createdConnection != null) { + Log.d(this, "adapter handleCreateConnectionSuccessful %s", + request.getCallId()); + if (createdConnection.getState() == Connection.State.INITIALIZING) { + // Wait for the connection to become initialized. + createdConnection.addConnectionListener(new Connection.Listener() { + @Override + public void onStateChanged(Connection c, int state) { + switch (state) { + case Connection.State.FAILED: + Log.d(this, "Connection (%s) failed (%d: %s)", request, + c.getFailureCode(), c.getFailureMessage()); + mAdapter.handleCreateConnectionFailed(request, c.getFailureCode(), + c.getFailureMessage()); + break; + case Connection.State.CANCELED: + Log.d(this, "Connection (%s) canceled", request); + mAdapter.handleCreateConnectionCancelled(request); + break; + case Connection.State.INITIALIZING: + Log.d(this, "State changed to INITIALIZING; ignoring"); + return; // Don't want to stop listening on this state transition. + default: + Log.d(this, "Connection created in state %s", + Connection.stateToString(state)); + connectionCreated(request, createdConnection); + break; + } + c.removeConnectionListener(this); + } + }); + } else if (createdConnection.getState() == Connection.State.CANCELED) { // Tell telecomm not to attempt any more services. mAdapter.handleCreateConnectionCancelled(request); + } else { + connectionCreated(request, createdConnection); } - }; - if (isIncoming) { - onCreateIncomingConnection(originalRequest, response); } else { - onCreateOutgoingConnection(originalRequest, response); + // Tell telecomm to try a different service. + mAdapter.handleCreateConnectionFailed(request, DisconnectCause.ERROR_UNSPECIFIED, null); } } + private void connectionCreated(ConnectionRequest request, Connection connection) { + addConnection(request.getCallId(), connection); + mAdapter.handleCreateConnectionSuccessful( + request, + new ParcelableConnection( + request.getAccountHandle(), + connection.getState(), + connection.getCallCapabilities(), + connection.getHandle(), + connection.getHandlePresentation(), + connection.getCallerDisplayName(), + connection.getCallerDisplayNamePresentation(), + connection.getVideoCallProvider() == null ? + null : connection.getVideoCallProvider().getInterface(), + connection.getVideoState())); + } + private void abort(String callId) { Log.d(this, "abort %s", callId); findConnectionForAction(callId, "abort").onAbort(); @@ -609,13 +642,6 @@ public abstract class ConnectionService extends Service { }); } - public final void lookupRemoteAccounts( - Uri handle, SimpleResponse<Uri, List<PhoneAccountHandle>> response) { - mAccountLookupResponse = response; - mAccountLookupHandle = handle; - maybeRespondToAccountLookup(); - } - public final void maybeRespondToAccountLookup() { if (mAreAccountsInitialized && mAccountLookupResponse != null) { mAccountLookupResponse.onResult( @@ -627,16 +653,12 @@ public abstract class ConnectionService extends Service { } } - public final void createRemoteIncomingConnection( - ConnectionRequest request, - CreateConnectionResponse<RemoteConnection> response) { - mRemoteConnectionManager.createRemoteConnection(request, response, true); + public final RemoteConnection createRemoteIncomingConnection(ConnectionRequest request) { + return mRemoteConnectionManager.createRemoteConnection(request, true); } - public final void createRemoteOutgoingConnection( - ConnectionRequest request, - CreateConnectionResponse<RemoteConnection> response) { - mRemoteConnectionManager.createRemoteConnection(request, response, false); + public final RemoteConnection createRemoteOutgoingConnection(ConnectionRequest request) { + return mRemoteConnectionManager.createRemoteConnection(request, false); } /** @@ -649,23 +671,22 @@ public abstract class ConnectionService extends Service { /** * Create a Connection given an incoming request. This is used to attach to existing incoming * calls. - * * @param request Details about the incoming call. - * @param callback A callback for providing the result. + * + * @return The {@link Connection} object to satisfy this call, or {@code null} to not handle + * the call. */ - public void onCreateIncomingConnection( - ConnectionRequest request, - CreateConnectionResponse<Connection> callback) {} + public Connection onCreateIncomingConnection(ConnectionRequest request) { return null; } /** * Create a Connection given an outgoing request. This is used to initiate new outgoing calls. + * @param request Details about the outgoing call. + * + * @return The {@link Connection} object to satisfy this request, + * or null to not handle the call. * - * @param request Details about the outgoing call. - * @param callback A callback for providing the result. */ - public void onCreateOutgoingConnection( - ConnectionRequest request, - CreateConnectionResponse<Connection> callback) {} + public Connection onCreateOutgoingConnection(ConnectionRequest request) { return null; } /** * Returns a new or existing conference connection when the the user elects to convert the @@ -742,4 +763,312 @@ public abstract class ConnectionService extends Service { Log.w(this, "%s - Cannot find Connection %s", action, callId); return NULL_CONNECTION; } + + public static abstract class VideoCallProvider { + private static final int MSG_SET_VIDEO_CALL_LISTENER = 1; + private static final int MSG_SET_CAMERA = 2; + private static final int MSG_SET_PREVIEW_SURFACE = 3; + private static final int MSG_SET_DISPLAY_SURFACE = 4; + private static final int MSG_SET_DEVICE_ORIENTATION = 5; + private static final int MSG_SET_ZOOM = 6; + private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7; + private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8; + private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; + private static final int MSG_REQUEST_CALL_DATA_USAGE = 10; + private static final int MSG_SET_PAUSE_IMAGE = 11; + + private final VideoCallProviderHandler mMessageHandler = new VideoCallProviderHandler(); + private final VideoCallProviderBinder mBinder; + private IVideoCallCallback mVideoCallListener; + + /** + * Default handler used to consolidate binder method calls onto a single thread. + */ + private final class VideoCallProviderHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SET_VIDEO_CALL_LISTENER: + mVideoCallListener = IVideoCallCallback.Stub.asInterface((IBinder) msg.obj); + break; + case MSG_SET_CAMERA: + onSetCamera((String) msg.obj); + break; + case MSG_SET_PREVIEW_SURFACE: + onSetPreviewSurface((Surface) msg.obj); + break; + case MSG_SET_DISPLAY_SURFACE: + onSetDisplaySurface((Surface) msg.obj); + break; + case MSG_SET_DEVICE_ORIENTATION: + onSetDeviceOrientation(msg.arg1); + break; + case MSG_SET_ZOOM: + onSetZoom((Float) msg.obj); + break; + case MSG_SEND_SESSION_MODIFY_REQUEST: + onSendSessionModifyRequest((VideoCallProfile) msg.obj); + break; + case MSG_SEND_SESSION_MODIFY_RESPONSE: + onSendSessionModifyResponse((VideoCallProfile) msg.obj); + break; + case MSG_REQUEST_CAMERA_CAPABILITIES: + onRequestCameraCapabilities(); + break; + case MSG_REQUEST_CALL_DATA_USAGE: + onRequestCallDataUsage(); + break; + case MSG_SET_PAUSE_IMAGE: + onSetPauseImage((String) msg.obj); + break; + default: + break; + } + } + } + + /** + * IVideoCallProvider stub implementation. + */ + private final class VideoCallProviderBinder extends IVideoCallProvider.Stub { + public void setVideoCallListener(IBinder videoCallListenerBinder) { + mMessageHandler.obtainMessage( + MSG_SET_VIDEO_CALL_LISTENER, videoCallListenerBinder).sendToTarget(); + } + + public void setCamera(String cameraId) { + mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget(); + } + + public void setPreviewSurface(Surface surface) { + mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget(); + } + + public void setDisplaySurface(Surface surface) { + mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget(); + } + + public void setDeviceOrientation(int rotation) { + mMessageHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation).sendToTarget(); + } + + public void setZoom(float value) { + mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget(); + } + + public void sendSessionModifyRequest(VideoCallProfile requestProfile) { + mMessageHandler.obtainMessage( + MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget(); + } + + public void sendSessionModifyResponse(VideoCallProfile responseProfile) { + mMessageHandler.obtainMessage( + MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget(); + } + + public void requestCameraCapabilities() { + mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget(); + } + + public void requestCallDataUsage() { + mMessageHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget(); + } + + public void setPauseImage(String uri) { + mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget(); + } + } + + public VideoCallProvider() { + mBinder = new VideoCallProviderBinder(); + } + + /** + * Returns binder object which can be used across IPC methods. + * @hide + */ + public final IVideoCallProvider getInterface() { + return mBinder; + } + + /** + * Sets the camera to be used for video recording in a video call. + * + * @param cameraId The id of the camera. + */ + public abstract void onSetCamera(String cameraId); + + /** + * Sets the surface to be used for displaying a preview of what the user's camera is + * currently capturing. When video transmission is enabled, this is the video signal which is + * sent to the remote device. + * + * @param surface The surface. + */ + public abstract void onSetPreviewSurface(Surface surface); + + /** + * Sets the surface to be used for displaying the video received from the remote device. + * + * @param surface The surface. + */ + public abstract void onSetDisplaySurface(Surface surface); + + /** + * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of the + * device is 0 degrees. + * + * @param rotation The device orientation, in degrees. + */ + public abstract void onSetDeviceOrientation(int rotation); + + /** + * Sets camera zoom ratio. + * + * @param value The camera zoom ratio. + */ + public abstract void onSetZoom(float value); + + /** + * Issues a request to modify the properties of the current session. The request is sent to + * the remote device where it it handled by + * {@link InCallService.VideoCall.Listener#onSessionModifyRequestReceived}. + * Some examples of session modification requests: upgrade call from audio to video, downgrade + * call from video to audio, pause video. + * + * @param requestProfile The requested call video properties. + */ + public abstract void onSendSessionModifyRequest(VideoCallProfile requestProfile); + + /**te + * Provides a response to a request to change the current call session video + * properties. + * This is in response to a request the InCall UI has received via + * {@link InCallService.VideoCall.Listener#onSessionModifyRequestReceived}. + * The response is handled on the remove device by + * {@link InCallService.VideoCall.Listener#onSessionModifyResponseReceived}. + * + * @param responseProfile The response call video properties. + */ + public abstract void onSendSessionModifyResponse(VideoCallProfile responseProfile); + + /** + * Issues a request to the video provider to retrieve the camera capabilities. + * Camera capabilities are reported back to the caller via + * {@link InCallService.VideoCall.Listener#onCameraCapabilitiesChanged(CallCameraCapabilities)}. + */ + public abstract void onRequestCameraCapabilities(); + + /** + * Issues a request to the video telephony framework to retrieve the cumulative data usage for + * the current call. Data usage is reported back to the caller via + * {@link InCallService.VideoCall.Listener#onCallDataUsageChanged}. + */ + public abstract void onRequestCallDataUsage(); + + /** + * Provides the video telephony framework with the URI of an image to be displayed to remote + * devices when the video signal is paused. + * + * @param uri URI of image to display. + */ + public abstract void onSetPauseImage(String uri); + + /** + * Invokes callback method defined in {@link InCallService.VideoCall.Listener}. + * + * @param videoCallProfile The requested video call profile. + */ + public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) { + if (mVideoCallListener != null) { + try { + mVideoCallListener.receiveSessionModifyRequest(videoCallProfile); + } catch (RemoteException ignored) { + } + } + } + + /** + * Invokes callback method defined in {@link InCallService.VideoCall.Listener}. + * + * @param status Status of the session modify request. Valid values are + * {@link InCallService.VideoCall#SESSION_MODIFY_REQUEST_SUCCESS}, + * {@link InCallService.VideoCall#SESSION_MODIFY_REQUEST_FAIL}, + * {@link InCallService.VideoCall#SESSION_MODIFY_REQUEST_INVALID} + * @param requestedProfile The original request which was sent to the remote device. + * @param responseProfile The actual profile changes made by the remote device. + */ + public void receiveSessionModifyResponse(int status, + VideoCallProfile requestedProfile, VideoCallProfile responseProfile) { + if (mVideoCallListener != null) { + try { + mVideoCallListener.receiveSessionModifyResponse( + status, requestedProfile, responseProfile); + } catch (RemoteException ignored) { + } + } + } + + /** + * Invokes callback method defined in {@link InCallService.VideoCall.Listener}. + * + * Valid values are: {@link InCallService.VideoCall#SESSION_EVENT_RX_PAUSE}, + * {@link InCallService.VideoCall#SESSION_EVENT_RX_RESUME}, + * {@link InCallService.VideoCall#SESSION_EVENT_TX_START}, + * {@link InCallService.VideoCall#SESSION_EVENT_TX_STOP} + * + * @param event The event. + */ + public void handleCallSessionEvent(int event) { + if (mVideoCallListener != null) { + try { + mVideoCallListener.handleCallSessionEvent(event); + } catch (RemoteException ignored) { + } + } + } + + /** + * Invokes callback method defined in {@link InCallService.VideoCall.Listener}. + * + * @param width The updated peer video width. + * @param height The updated peer video height. + */ + public void changePeerDimensions(int width, int height) { + if (mVideoCallListener != null) { + try { + mVideoCallListener.changePeerDimensions(width, height); + } catch (RemoteException ignored) { + } + } + } + + /** + * Invokes callback method defined in {@link InCallService.VideoCall.Listener}. + * + * @param dataUsage The updated data usage. + */ + public void changeCallDataUsage(int dataUsage) { + if (mVideoCallListener != null) { + try { + mVideoCallListener.changeCallDataUsage(dataUsage); + } catch (RemoteException ignored) { + } + } + } + + /** + * Invokes callback method defined in {@link InCallService.VideoCall.Listener}. + * + * @param callCameraCapabilities The changed camera capabilities. + */ + public void changeCameraCapabilities(CallCameraCapabilities callCameraCapabilities) { + if (mVideoCallListener != null) { + try { + mVideoCallListener.changeCameraCapabilities(callCameraCapabilities); + } catch (RemoteException ignored) { + } + } + } + } } diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java index 66e99252fbf9..ea61362ac7ec 100644 --- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java +++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java @@ -25,7 +25,7 @@ import android.os.RemoteException; import com.android.internal.telecomm.IConnectionService; import com.android.internal.telecomm.IConnectionServiceAdapter; -import com.android.internal.telecomm.ICallVideoProvider; +import com.android.internal.telecomm.IVideoCallProvider; import com.android.internal.telecomm.RemoteServiceCallback; import java.util.ArrayList; @@ -273,14 +273,15 @@ final class ConnectionServiceAdapter implements DeathRecipient { * Sets the call video provider for a call. * * @param callId The unique ID of the call to set with the given call video provider. - * @param callVideoProvider The call video provider instance to set on the call. + * @param videoCallProvider The call video provider instance to set on the call. */ - void setCallVideoProvider(String callId, CallVideoProvider callVideoProvider) { + void setVideoCallProvider( + String callId, ConnectionService.VideoCallProvider videoCallProvider) { for (IConnectionServiceAdapter adapter : mAdapters) { try { - adapter.setCallVideoProvider( + adapter.setVideoCallProvider( callId, - callVideoProvider == null ? null : callVideoProvider.getInterface()); + videoCallProvider == null ? null : videoCallProvider.getInterface()); } catch (RemoteException e) { } } diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java index 9699e2aa83e8..14b25dc804dd 100644 --- a/telecomm/java/android/telecomm/InCallService.java +++ b/telecomm/java/android/telecomm/InCallService.java @@ -23,11 +23,14 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.view.Surface; import com.android.internal.os.SomeArgs; import com.android.internal.telecomm.IInCallAdapter; import com.android.internal.telecomm.IInCallService; +import java.lang.String; + /** * This service is implemented by any app that wishes to provide the user-interface for managing * phone calls. Telecomm binds to this service while there exists a live (active or incoming) call, @@ -196,4 +199,210 @@ public abstract class InCallService extends Service { */ public void onPhoneDestroyed(Phone phone) { } + + /** + * Class to invoke functionality related to video calls. + */ + public static abstract class VideoCall { + + /** + * Video is not being received (no protocol pause was issued). + */ + public static final int SESSION_EVENT_RX_PAUSE = 1; + + /** + * Video reception has resumed after a SESSION_EVENT_RX_PAUSE. + */ + public static final int SESSION_EVENT_RX_RESUME = 2; + + /** + * Video transmission has begun. This occurs after a negotiated start of video transmission + * when the underlying protocol has actually begun transmitting video to the remote party. + */ + public static final int SESSION_EVENT_TX_START = 3; + + /** + * Video transmission has stopped. This occur after a negotiated stop of video transmission when + * the underlying protocol has actually stopped transmitting video to the remote party. + */ + public static final int SESSION_EVENT_TX_STOP = 4; + + /** + * Session modify request was successful. + */ + public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; + + /** + * Session modify request failed. + */ + public static final int SESSION_MODIFY_REQUEST_FAIL = 2; + + /** + * Session modify request ignored due to invalid parameters. + */ + public static final int SESSION_MODIFY_REQUEST_INVALID = 3; + + /** + * Sets a listener to invoke callback methods in the InCallUI after performing video + * telephony actions. + * + * @param videoCallListener The call video client. + */ + public abstract void setVideoCallListener(VideoCall.Listener videoCallListener); + + /** + * Sets the camera to be used for video recording in a video call. + * + * @param cameraId The id of the camera. + */ + public abstract void setCamera(String cameraId); + + /** + * Sets the surface to be used for displaying a preview of what the user's camera is + * currently capturing. When video transmission is enabled, this is the video signal which + * is sent to the remote device. + * + * @param surface The surface. + */ + public abstract void setPreviewSurface(Surface surface); + + /** + * Sets the surface to be used for displaying the video received from the remote device. + * + * @param surface The surface. + */ + public abstract void setDisplaySurface(Surface surface); + + /** + * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of + * the device is 0 degrees. + * + * @param rotation The device orientation, in degrees. + */ + public abstract void setDeviceOrientation(int rotation); + + /** + * Sets camera zoom ratio. + * + * @param value The camera zoom ratio. + */ + public abstract void setZoom(float value); + + /** + * Issues a request to modify the properties of the current session. The request is sent to + * the remote device where it it handled by + * {@link VideoCall.Listener#onSessionModifyRequestReceived}. + * Some examples of session modification requests: upgrade call from audio to video, + * downgrade call from video to audio, pause video. + * + * @param requestProfile The requested call video properties. + */ + public abstract void sendSessionModifyRequest(VideoCallProfile requestProfile); + + /** + * Provides a response to a request to change the current call session video + * properties. + * This is in response to a request the InCall UI has received via + * {@link VideoCall.Listener#onSessionModifyRequestReceived}. + * The response is handled on the remove device by + * {@link VideoCall.Listener#onSessionModifyResponseReceived}. + * + * @param responseProfile The response call video properties. + */ + public abstract void sendSessionModifyResponse(VideoCallProfile responseProfile); + + /** + * Issues a request to the video provider to retrieve the camera capabilities. + * Camera capabilities are reported back to the caller via + * {@link VideoCall.Listener#onCameraCapabilitiesChanged(CallCameraCapabilities)}. + */ + public abstract void requestCameraCapabilities(); + + /** + * Issues a request to the video telephony framework to retrieve the cumulative data usage for + * the current call. Data usage is reported back to the caller via + * {@link VideoCall.Listener#onCallDataUsageChanged}. + */ + public abstract void requestCallDataUsage(); + + /** + * Provides the video telephony framework with the URI of an image to be displayed to remote + * devices when the video signal is paused. + * + * @param uri URI of image to display. + */ + public abstract void setPauseImage(String uri); + + /** + * Listener class which invokes callbacks after video call actions occur. + */ + public static abstract class Listener { + /** + * Called when a session modification request is received from the remote device. + * The remote request is sent via + * {@link ConnectionService.VideoCallProvider#onSendSessionModifyRequest}. The InCall UI + * is responsible for potentially prompting the user whether they wish to accept the new + * call profile (e.g. prompt user if they wish to accept an upgrade from an audio to a + * video call) and should call + * {@link ConnectionService.VideoCallProvider#onSendSessionModifyResponse} to indicate + * the video settings the user has agreed to. + * + * @param videoCallProfile The requested video call profile. + */ + public abstract void onSessionModifyRequestReceived(VideoCallProfile videoCallProfile); + + /** + * Called when a response to a session modification request is received from the remote + * device. The remote InCall UI sends the response using + * {@link ConnectionService.VideoCallProvider#onSendSessionModifyResponse}. + * + * @param status Status of the session modify request. Valid values are + * {@link VideoCall#SESSION_MODIFY_REQUEST_SUCCESS}, + * {@link VideoCall#SESSION_MODIFY_REQUEST_FAIL}, + * {@link VideoCall#SESSION_MODIFY_REQUEST_INVALID} + * @param requestedProfile The original request which was sent to the remote device. + * @param responseProfile The actual profile changes made by the remote device. + */ + public abstract void onSessionModifyResponseReceived(int status, + VideoCallProfile requestedProfile, VideoCallProfile responseProfile); + + /** + * Handles events related to the current session which the client may wish to handle. + * These are separate from requested changes to the session due to the underlying + * protocol or connection. + * + * Valid values are: {@link VideoCall#SESSION_EVENT_RX_PAUSE}, + * {@link VideoCall#SESSION_EVENT_RX_RESUME}, + * {@link VideoCall#SESSION_EVENT_TX_START}, + * {@link VideoCall#SESSION_EVENT_TX_STOP} + * + * @param event The event. + */ + public abstract void onCallSessionEvent(int event); + + /** + * Handles a change to the video dimensions from the remote caller (peer). This could + * happen if, for example, the peer changes orientation of their device. + * + * @param width The updated peer video width. + * @param height The updated peer video height. + */ + public abstract void onPeerDimensionsChanged(int width, int height); + + /** + * Handles an update to the total data used for the current session. + * + * @param dataUsage The updated data usage. + */ + public abstract void onCallDataUsageChanged(int dataUsage); + + /** + * Handles a change in camera capabilities. + * + * @param callCameraCapabilities The changed camera capabilities. + */ + public abstract void onCameraCapabilitiesChanged( + CallCameraCapabilities callCameraCapabilities); + } + } } diff --git a/telecomm/java/android/telecomm/ParcelableCall.java b/telecomm/java/android/telecomm/ParcelableCall.java index 27a5c1d90826..e60761ac6567 100644 --- a/telecomm/java/android/telecomm/ParcelableCall.java +++ b/telecomm/java/android/telecomm/ParcelableCall.java @@ -22,7 +22,7 @@ import android.os.Parcelable; import android.os.RemoteException; import android.telephony.DisconnectCause; -import com.android.internal.telecomm.ICallVideoProvider; +import com.android.internal.telecomm.IVideoCallProvider; import java.util.ArrayList; import java.util.List; @@ -45,8 +45,8 @@ public final class ParcelableCall implements Parcelable { private final int mCallerDisplayNamePresentation; private final GatewayInfo mGatewayInfo; private final PhoneAccountHandle mAccountHandle; - private final ICallVideoProvider mCallVideoProvider; - private RemoteCallVideoProvider mRemoteCallVideoProvider; + private final IVideoCallProvider mVideoCallProvider; + private InCallService.VideoCall mVideoCall; private final String mParentCallId; private final List<String> mChildCallIds; private final StatusHints mStatusHints; @@ -67,7 +67,7 @@ public final class ParcelableCall implements Parcelable { int callerDisplayNamePresentation, GatewayInfo gatewayInfo, PhoneAccountHandle accountHandle, - ICallVideoProvider callVideoProvider, + IVideoCallProvider videoCallProvider, String parentCallId, List<String> childCallIds, StatusHints statusHints, @@ -85,7 +85,7 @@ public final class ParcelableCall implements Parcelable { mCallerDisplayNamePresentation = callerDisplayNamePresentation; mGatewayInfo = gatewayInfo; mAccountHandle = accountHandle; - mCallVideoProvider = callVideoProvider; + mVideoCallProvider = videoCallProvider; mParentCallId = parentCallId; mChildCallIds = childCallIds; mStatusHints = statusHints; @@ -166,19 +166,19 @@ public final class ParcelableCall implements Parcelable { } /** - * Returns an object for remotely communicating through the call video provider's binder. - * @return The call video provider. + * Returns an object for remotely communicating through the video call provider's binder. + * @return The video call. */ - public RemoteCallVideoProvider getCallVideoProvider() throws RemoteException { - if (mRemoteCallVideoProvider == null && mCallVideoProvider != null) { + public InCallService.VideoCall getVideoCall() { + if (mVideoCall == null && mVideoCallProvider != null) { try { - mRemoteCallVideoProvider = new RemoteCallVideoProvider(mCallVideoProvider); + mVideoCall = new VideoCallImpl(mVideoCallProvider); } catch (RemoteException ignored) { // Ignore RemoteException. } } - return mRemoteCallVideoProvider; + return mVideoCall; } /** @@ -235,8 +235,8 @@ public final class ParcelableCall implements Parcelable { int callerDisplayNamePresentation = source.readInt(); GatewayInfo gatewayInfo = source.readParcelable(classLoader); PhoneAccountHandle accountHandle = source.readParcelable(classLoader); - ICallVideoProvider callVideoProvider = - ICallVideoProvider.Stub.asInterface(source.readStrongBinder()); + IVideoCallProvider videoCallProvider = + IVideoCallProvider.Stub.asInterface(source.readStrongBinder()); String parentCallId = source.readString(); List<String> childCallIds = new ArrayList<>(); source.readList(childCallIds, classLoader); @@ -245,7 +245,7 @@ public final class ParcelableCall implements Parcelable { return new ParcelableCall(id, state, disconnectCauseCode, disconnectCauseMsg, cannedSmsResponses, capabilities, connectTimeMillis, handle, handlePresentation, callerDisplayName, callerDisplayNamePresentation, gatewayInfo, - accountHandle, callVideoProvider, parentCallId, childCallIds, statusHints, + accountHandle, videoCallProvider, parentCallId, childCallIds, statusHints, videoState); } @@ -278,7 +278,7 @@ public final class ParcelableCall implements Parcelable { destination.writeParcelable(mGatewayInfo, 0); destination.writeParcelable(mAccountHandle, 0); destination.writeStrongBinder( - mCallVideoProvider != null ? mCallVideoProvider.asBinder() : null); + mVideoCallProvider != null ? mVideoCallProvider.asBinder() : null); destination.writeString(mParentCallId); destination.writeList(mChildCallIds); destination.writeParcelable(mStatusHints, 0); diff --git a/telecomm/java/android/telecomm/ParcelableConnection.java b/telecomm/java/android/telecomm/ParcelableConnection.java index f730fef12bf5..e0bfab6e9359 100644 --- a/telecomm/java/android/telecomm/ParcelableConnection.java +++ b/telecomm/java/android/telecomm/ParcelableConnection.java @@ -20,7 +20,7 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.telecomm.ICallVideoProvider; +import com.android.internal.telecomm.IVideoCallProvider; /** * Information about a connection that is used between Telecomm and the ConnectionService. @@ -36,7 +36,7 @@ public final class ParcelableConnection implements Parcelable { private int mHandlePresentation; private String mCallerDisplayName; private int mCallerDisplayNamePresentation; - private ICallVideoProvider mCallVideoProvider; + private IVideoCallProvider mVideoCallProvider; private int mVideoState; /** @hide */ @@ -48,7 +48,7 @@ public final class ParcelableConnection implements Parcelable { int handlePresentation, String callerDisplayName, int callerDisplayNamePresentation, - ICallVideoProvider callVideoProvider, + IVideoCallProvider videoCallProvider, int videoState) { mPhoneAccount = phoneAccount; mState = state; @@ -57,7 +57,7 @@ public final class ParcelableConnection implements Parcelable { mHandlePresentation = handlePresentation; mCallerDisplayName = callerDisplayName; mCallerDisplayNamePresentation = callerDisplayNamePresentation; - mCallVideoProvider = callVideoProvider; + mVideoCallProvider = videoCallProvider; mVideoState = videoState; } @@ -90,8 +90,8 @@ public final class ParcelableConnection implements Parcelable { return mCallerDisplayNamePresentation; } - public ICallVideoProvider getCallVideoProvider() { - return mCallVideoProvider; + public IVideoCallProvider getVideoCallProvider() { + return mVideoCallProvider; } public int getVideoState() { @@ -111,8 +111,8 @@ public final class ParcelableConnection implements Parcelable { int handlePresentation = source.readInt(); String callerDisplayName = source.readString(); int callerDisplayNamePresentation = source.readInt(); - ICallVideoProvider callVideoProvider = - ICallVideoProvider.Stub.asInterface(source.readStrongBinder()); + IVideoCallProvider videoCallProvider = + IVideoCallProvider.Stub.asInterface(source.readStrongBinder()); int videoState = source.readInt(); return new ParcelableConnection( @@ -123,7 +123,7 @@ public final class ParcelableConnection implements Parcelable { handlePresentation, callerDisplayName, callerDisplayNamePresentation, - callVideoProvider, + videoCallProvider, videoState); } @@ -150,7 +150,7 @@ public final class ParcelableConnection implements Parcelable { destination.writeString(mCallerDisplayName); destination.writeInt(mCallerDisplayNamePresentation); destination.writeStrongBinder( - mCallVideoProvider != null ? mCallVideoProvider.asBinder() : null); + mVideoCallProvider != null ? mVideoCallProvider.asBinder() : null); destination.writeInt(mVideoState); } } diff --git a/telecomm/java/android/telecomm/RemoteCallVideoClient.java b/telecomm/java/android/telecomm/RemoteCallVideoClient.java deleted file mode 100644 index 08d1391fc689..000000000000 --- a/telecomm/java/android/telecomm/RemoteCallVideoClient.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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 android.telecomm; - -import android.os.IBinder; -import android.os.RemoteException; -import android.telecomm.CallCameraCapabilities; -import android.telecomm.VideoCallProfile; - -import com.android.internal.telecomm.ICallVideoClient; - -/** - * Remote class to invoke callbacks in InCallUI related to supporting video in calls. - */ -public class RemoteCallVideoClient { - private final ICallVideoClient mCallVideoClient; - - private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { - @Override - public void binderDied() { - mCallVideoClient.asBinder().unlinkToDeath(this, 0); - } - }; - - /** {@hide} */ - RemoteCallVideoClient(ICallVideoClient callVideoProvider) throws RemoteException { - mCallVideoClient = callVideoProvider; - mCallVideoClient.asBinder().linkToDeath(mDeathRecipient, 0); - } - - /** - * Called when a session modification request is received from the remote device. - * The remote request is sent via {@link CallVideoProvider#onSendSessionModifyRequest}. - * The InCall UI is responsible for potentially prompting the user whether they wish to accept - * the new call profile (e.g. prompt user if they wish to accept an upgrade from an audio to a - * video call) and should call {@link CallVideoProvider#onSendSessionModifyResponse} to indicate - * the video settings the user has agreed to. - * - * @param videoCallProfile The requested video call profile. - */ - public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) { - try { - mCallVideoClient.receiveSessionModifyRequest(videoCallProfile); - } catch (RemoteException e) { - } - } - - /** - * Called when a response to a session modification request is received from the remote device. - * The remote InCall UI sends the response using - * {@link CallVideoProvider#onSendSessionModifyResponse}. - * - * @param status Status of the session modify request. Valid values are - * {@link CallVideoClient#SESSION_MODIFY_REQUEST_SUCCESS}, - * {@link CallVideoClient#SESSION_MODIFY_REQUEST_FAIL}, - * {@link CallVideoClient#SESSION_MODIFY_REQUEST_INVALID} - * @param requestedProfile The original request which was sent to the remote device. - * @param responseProfile The actual profile changes made by the remote device. - */ - public void receiveSessionModifyResponse( - int status, VideoCallProfile requestedProfile, VideoCallProfile responseProfile) { - try { - mCallVideoClient.receiveSessionModifyResponse( - status, requestedProfile, responseProfile); - } catch (RemoteException e) { - } - } - - /** - * Handles events related to the current session which the client may wish to handle. These - * are separate from requested changes to the session due to the underlying protocol or - * connection. - * Valid values are: {@link CallVideoClient#SESSION_EVENT_RX_PAUSE}, - * {@link CallVideoClient#SESSION_EVENT_RX_RESUME}, - * {@link CallVideoClient#SESSION_EVENT_TX_START}, {@link CallVideoClient#SESSION_EVENT_TX_STOP} - * - * @param event The event. - */ - public void handleCallSessionEvent(int event) { - try { - mCallVideoClient.handleCallSessionEvent(event); - } catch (RemoteException e) { - } - } - - /** - * Handles a change to the video dimensions from the remote caller (peer). This could happen - * if, for example, the peer changes orientation of their device. - * - * @param width The updated peer video width. - * @param height The updated peer video height. - */ - public void updatePeerDimensions(int width, int height) { - try { - mCallVideoClient.updatePeerDimensions(width, height); - } catch (RemoteException e) { - } - } - - /** - * Handles an update to the total data used for the current session. - * - * @param dataUsage The updated data usage. - */ - public void updateCallDataUsage(int dataUsage) { - try { - mCallVideoClient.updateCallDataUsage(dataUsage); - } catch (RemoteException e) { - } - } - - /** - * Handles a change in camera capabilities. - * - * @param callCameraCapabilities The changed camera capabilities. - */ - public void handleCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities) { - try { - mCallVideoClient.handleCameraCapabilitiesChange(callCameraCapabilities); - } catch (RemoteException e) { - } - } -}
\ No newline at end of file diff --git a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java b/telecomm/java/android/telecomm/RemoteCallVideoProvider.java deleted file mode 100644 index b8b8b9dee426..000000000000 --- a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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 android.telecomm; - -import android.os.IBinder; -import android.os.RemoteException; -import android.view.Surface; - -import com.android.internal.telecomm.ICallVideoProvider; - -/** - * Remote class for InCallUI to invoke functionality provided for video in calls. - */ -public class RemoteCallVideoProvider { - private final ICallVideoProvider mCallVideoProvider; - - private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { - @Override - public void binderDied() { - mCallVideoProvider.asBinder().unlinkToDeath(this, 0); - } - }; - - /** {@hide} */ - RemoteCallVideoProvider(ICallVideoProvider callVideoProvider) throws RemoteException { - mCallVideoProvider = callVideoProvider; - mCallVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0); - } - - /** - * Sets a remote interface for invoking callback methods in the InCallUI after performing - * telephony actions. - * - * @param callVideoClient The call video client. - */ - public void setCallVideoClient(CallVideoClient callVideoClient) { - try { - mCallVideoProvider.setCallVideoClient(callVideoClient.getBinder()); - } catch (RemoteException e) { - } - } - - /** - * Sets the camera to be used for video recording in a video call. - * - * @param cameraId The id of the camera. - */ - public void setCamera(String cameraId) { - try { - mCallVideoProvider.setCamera(cameraId); - } catch (RemoteException e) { - } - } - - /** - * Sets the surface to be used for displaying a preview of what the user's camera is - * currently capturing. When video transmission is enabled, this is the video signal which is - * sent to the remote device. - * - * @param surface The surface. - */ - public void setPreviewSurface(Surface surface) { - try { - mCallVideoProvider.setPreviewSurface(surface); - } catch (RemoteException e) { - } - } - - /** - * Sets the surface to be used for displaying the video received from the remote device. - * - * @param surface The surface. - */ - public void setDisplaySurface(Surface surface) { - try { - mCallVideoProvider.setDisplaySurface(surface); - } catch (RemoteException e) { - } - } - - /** - * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of the - * device is 0 degrees. - * - * @param rotation The device orientation, in degrees. - */ - public void setDeviceOrientation(int rotation) { - try { - mCallVideoProvider.setDeviceOrientation(rotation); - } catch (RemoteException e) { - } - } - - /** - * Sets camera zoom ratio. - * - * @param value The camera zoom ratio. - */ - public void setZoom(float value) { - try { - mCallVideoProvider.setZoom(value); - } catch (RemoteException e) { - } - } - - /** - * Issues a request to modify the properties of the current session. The request is sent to - * the remote device where it it handled by - * {@link CallVideoClient#onReceiveSessionModifyRequest}. - * Some examples of session modification requests: upgrade call from audio to video, downgrade - * call from video to audio, pause video. - * - * @param requestProfile The requested call video properties. - */ - public void sendSessionModifyRequest(VideoCallProfile requestProfile) { - try { - mCallVideoProvider.sendSessionModifyRequest(requestProfile); - } catch (RemoteException e) { - } - } - - /** - * Provides a response to a request to change the current call session video - * properties. - * This is in response to a request the InCall UI has received via - * {@link CallVideoClient#onReceiveSessionModifyRequest}. - * The response is handled on the remove device by - * {@link CallVideoClient#onReceiveSessionModifyResponse}. - * - * @param responseProfile The response call video properties. - */ - public void sendSessionModifyResponse(VideoCallProfile responseProfile) { - try { - mCallVideoProvider.sendSessionModifyResponse(responseProfile); - } catch (RemoteException e) { - } - } - - /** - * Issues a request to the video provider to retrieve the camera capabilities. - * Camera capabilities are reported back to the caller via - * {@link CallVideoClient#onHandleCameraCapabilitiesChange(CallCameraCapabilities)}. - */ - public void requestCameraCapabilities() { - try { - mCallVideoProvider.requestCameraCapabilities(); - } catch (RemoteException e) { - } - } - - /** - * Issues a request to the video telephony framework to retrieve the cumulative data usage for - * the current call. Data usage is reported back to the caller via - * {@link CallVideoClient#onUpdateCallDataUsage}. - */ - public void requestCallDataUsage() { - try { - mCallVideoProvider.requestCallDataUsage(); - } catch (RemoteException e) { - } - } - - /** - * Provides the video telephony framework with the URI of an image to be displayed to remote - * devices when the video signal is paused. - * - * @param uri URI of image to display. - */ - public void setPauseImage(String uri) { - try { - mCallVideoProvider.setPauseImage(uri); - } catch (RemoteException e) { - } - } -}
\ No newline at end of file diff --git a/telecomm/java/android/telecomm/RemoteConnection.java b/telecomm/java/android/telecomm/RemoteConnection.java index ddad58f8b12a..ab980e8259e7 100644 --- a/telecomm/java/android/telecomm/RemoteConnection.java +++ b/telecomm/java/android/telecomm/RemoteConnection.java @@ -18,7 +18,6 @@ package android.telecomm; import android.app.PendingIntent; import android.net.Uri; -import android.os.Bundle; import android.os.RemoteException; import android.telephony.DisconnectCause; @@ -31,23 +30,23 @@ import java.util.Set; * RemoteConnection object used by RemoteConnectionService. */ public final class RemoteConnection { - public interface Listener { - void onStateChanged(RemoteConnection connection, int state); - void onDisconnected(RemoteConnection connection, int cause, String message); - void onRequestingRingback(RemoteConnection connection, boolean ringback); - void onCallCapabilitiesChanged(RemoteConnection connection, int callCapabilities); - void onPostDialWait(RemoteConnection connection, String remainingDigits); - void onAudioModeIsVoipChanged(RemoteConnection connection, boolean isVoip); - void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints); - void onHandleChanged(RemoteConnection connection, Uri handle, int presentation); - void onCallerDisplayNameChanged( - RemoteConnection connection, String callerDisplayName, int presentation); - void onVideoStateChanged(RemoteConnection connection, int videoState); - void onStartActivityFromInCall(RemoteConnection connection, PendingIntent intent); - void onDestroyed(RemoteConnection connection); - } - - private final IConnectionService mConnectionService; + public static abstract class Listener { + public void onStateChanged(RemoteConnection connection, int state) {} + public void onDisconnected(RemoteConnection connection, int cause, String message) {} + public void onRequestingRingback(RemoteConnection connection, boolean ringback) {} + public void onCallCapabilitiesChanged(RemoteConnection connection, int callCapabilities) {} + public void onPostDialWait(RemoteConnection connection, String remainingDigits) {} + public void onAudioModeIsVoipChanged(RemoteConnection connection, boolean isVoip) {} + public void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints) {} + public void onHandleChanged(RemoteConnection connection, Uri handle, int presentation) {} + public void onCallerDisplayNameChanged( + RemoteConnection connection, String callerDisplayName, int presentation) {} + public void onVideoStateChanged(RemoteConnection connection, int videoState) {} + public void onStartActivityFromInCall(RemoteConnection connection, PendingIntent intent) {} + public void onDestroyed(RemoteConnection connection) {} + } + + private IConnectionService mConnectionService; private final String mConnectionId; private final Set<Listener> mListeners = new HashSet<>(); @@ -64,15 +63,35 @@ public final class RemoteConnection { private int mHandlePresentation; private String mCallerDisplayName; private int mCallerDisplayNamePresentation; + private int mFailureCode; + private String mFailureMessage; /** * @hide */ - RemoteConnection(IConnectionService connectionService, String connectionId) { + RemoteConnection(IConnectionService connectionService, ConnectionRequest request, + boolean isIncoming) { mConnectionService = connectionService; - mConnectionId = connectionId; + mConnectionId = request.getCallId(); mConnected = true; + mState = Connection.State.INITIALIZING; + } + + /** + * Create a RemoteConnection which is used for failed connections. Note that using it for any + * "real" purpose will almost certainly fail. Callers should note the failure and act + * accordingly (moving on to another RemoteConnection, for example) + * + * @param failureCode + * @param failureMessage + */ + private RemoteConnection(int failureCode, String failureMessage) { + this(null, null, true); + mConnected = false; + mState = Connection.State.FAILED; + mFailureCode = failureCode; + mFailureMessage = failureMessage; } public void addListener(Listener listener) { @@ -127,6 +146,14 @@ public final class RemoteConnection { return mVideoState; } + public int getFailureCode() { + return mFailureCode; + } + + public String getFailureMessage() { + return mFailureMessage; + } + public void abort() { try { if (mConnected) { @@ -354,4 +381,24 @@ public final class RemoteConnection { l.onStartActivityFromInCall(this, intent); } } + + /** @hide */ + void setConnectionService(IConnectionService connectionService) { + mConnectionService = connectionService; + mConnectionService = null; + setState(Connection.State.NEW); + } + + /** + * Create a RemoteConnection which is in the {@link Connection.State#FAILED} state. Attempting + * to use it for anything will almost certainly result in bad things happening. Do not do this. + * + * @return a failed {@link RemoteConnection} + * + * @hide + * + */ + public static RemoteConnection failure(int failureCode, String failureMessage) { + return new RemoteConnection(failureCode, failureMessage); + } } diff --git a/telecomm/java/android/telecomm/RemoteConnectionManager.java b/telecomm/java/android/telecomm/RemoteConnectionManager.java index b2d3dc73dff1..3ca68a2d811e 100644 --- a/telecomm/java/android/telecomm/RemoteConnectionManager.java +++ b/telecomm/java/android/telecomm/RemoteConnectionManager.java @@ -46,17 +46,11 @@ public class RemoteConnectionManager { List<PhoneAccountHandle> getAccounts(Uri handle) { List<PhoneAccountHandle> accountHandles = new LinkedList<>(); - Log.d(this, "Getting accountHandles: " + mRemoteConnectionServices.keySet()); - for (RemoteConnectionService remoteService : mRemoteConnectionServices.values()) { - // TODO(santoscordon): Eventually this will be async. - accountHandles.addAll(remoteService.lookupAccounts(handle)); - } return accountHandles; } - public void createRemoteConnection( + public RemoteConnection createRemoteConnection( ConnectionRequest request, - ConnectionService.CreateConnectionResponse response, boolean isIncoming) { PhoneAccountHandle accountHandle = request.getAccountHandle(); if (accountHandle == null) { @@ -67,9 +61,12 @@ public class RemoteConnectionManager { if (!mRemoteConnectionServices.containsKey(componentName)) { throw new UnsupportedOperationException("accountHandle not supported: " + componentName); - } else { - RemoteConnectionService remoteService = mRemoteConnectionServices.get(componentName); - remoteService.createRemoteConnection(request, response, isIncoming); } + + RemoteConnectionService remoteService = mRemoteConnectionServices.get(componentName); + if (remoteService != null) { + return remoteService.createRemoteConnection(request, isIncoming); + } + return null; } } diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java index 10569abc0cca..e6f47d2a7218 100644 --- a/telecomm/java/android/telecomm/RemoteConnectionService.java +++ b/telecomm/java/android/telecomm/RemoteConnectionService.java @@ -27,9 +27,9 @@ import android.telephony.DisconnectCause; import android.text.TextUtils; import com.android.internal.os.SomeArgs; -import com.android.internal.telecomm.ICallVideoProvider; import com.android.internal.telecomm.IConnectionService; import com.android.internal.telecomm.IConnectionServiceAdapter; +import com.android.internal.telecomm.IVideoCallProvider; import com.android.internal.telecomm.RemoteServiceCallback; import java.util.LinkedList; @@ -69,8 +69,6 @@ final class RemoteConnectionService implements DeathRecipient { private final ComponentName mComponentName; private String mConnectionId; - private ConnectionRequest mPendingRequest; - private ConnectionService.CreateConnectionResponse<RemoteConnection> mPendingResponse; // Remote connection services only support a single connection. private RemoteConnection mConnection; @@ -84,8 +82,6 @@ final class RemoteConnectionService implements DeathRecipient { ConnectionRequest request = (ConnectionRequest) args.arg1; if (isPendingConnection(request.getCallId())) { ParcelableConnection parcel = (ParcelableConnection) args.arg2; - mConnection = new RemoteConnection( - mConnectionService, request.getCallId()); mConnection.setState(parcel.getState()); mConnection.setCallCapabilities(parcel.getCapabilities()); mConnection.setHandle( @@ -94,9 +90,6 @@ final class RemoteConnectionService implements DeathRecipient { parcel.getCallerDisplayName(), parcel.getCallerDisplayNamePresentation()); // TODO: Do we need to support video providers for remote connections? - - mPendingResponse.onSuccess(request, mConnection); - clearPendingInformation(); } } finally { args.recycle(); @@ -108,9 +101,8 @@ final class RemoteConnectionService implements DeathRecipient { try { ConnectionRequest request = (ConnectionRequest) args.arg1; if (isPendingConnection(request.getCallId())) { - mPendingResponse.onFailure(request, args.argi1, (String) args.arg2); - mConnectionId = null; - clearPendingInformation(); + // TODO: How do we propogate the failure codes? + destroyConnection(); } } finally { args.recycle(); @@ -120,9 +112,7 @@ final class RemoteConnectionService implements DeathRecipient { case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: { ConnectionRequest request = (ConnectionRequest) msg.obj; if (isPendingConnection(request.getCallId())) { - mPendingResponse.onCancel(request); - mConnectionId = null; - clearPendingInformation(); + destroyConnection(); } break; } @@ -360,8 +350,8 @@ final class RemoteConnectionService implements DeathRecipient { } @Override - public void setCallVideoProvider( - String connectionId, ICallVideoProvider callVideoProvider) { + public void setVideoCallProvider( + String connectionId, IVideoCallProvider videoCallProvider) { // not supported for remote connections. } @@ -431,11 +421,7 @@ final class RemoteConnectionService implements DeathRecipient { release(); } - final void createRemoteConnection( - ConnectionRequest request, - ConnectionService.CreateConnectionResponse<RemoteConnection> response, - boolean isIncoming) { - + final RemoteConnection createRemoteConnection(ConnectionRequest request, boolean isIncoming) { if (mConnectionId == null) { String id = UUID.randomUUID().toString(); ConnectionRequest newRequest = new ConnectionRequest( @@ -445,29 +431,20 @@ final class RemoteConnectionService implements DeathRecipient { request.getHandlePresentation(), request.getExtras(), request.getVideoState()); + mConnection = new RemoteConnection(mConnectionService, request, isIncoming); try { mConnectionService.createConnection(newRequest, isIncoming); mConnectionId = id; - mPendingResponse = response; - mPendingRequest = request; } catch (RemoteException e) { - response.onFailure(request, DisconnectCause.ERROR_UNSPECIFIED, e.toString()); + mConnection = RemoteConnection.failure(DisconnectCause.ERROR_UNSPECIFIED, + e.toString()); } + return mConnection; } else { - response.onFailure(request, DisconnectCause.ERROR_UNSPECIFIED, null); + return RemoteConnection.failure(DisconnectCause.ERROR_UNSPECIFIED, null); } } - final List<PhoneAccountHandle> lookupAccounts(Uri handle) { - // TODO(santoscordon): Update this so that is actually calls into the RemoteConnection - // each time. - List<PhoneAccountHandle> accounts = new LinkedList<>(); - accounts.add(new PhoneAccountHandle( - mComponentName, - null /* id */)); - return accounts; - } - /** * Releases the resources associated with this Remote connection service. Should be called when * the remote service is no longer being used. @@ -477,7 +454,7 @@ final class RemoteConnectionService implements DeathRecipient { } private boolean isPendingConnection(String id) { - return TextUtils.equals(mConnectionId, id) && mPendingResponse != null; + return TextUtils.equals(mConnectionId, id); } private boolean isCurrentConnection(Object obj) { @@ -485,11 +462,6 @@ final class RemoteConnectionService implements DeathRecipient { TextUtils.equals(mConnectionId, (String) obj); } - private void clearPendingInformation() { - mPendingRequest = null; - mPendingResponse = null; - } - private void destroyConnection() { mConnection.setDestroyed(); mConnection = null; diff --git a/telecomm/java/android/telecomm/VideoCallImpl.java b/telecomm/java/android/telecomm/VideoCallImpl.java new file mode 100644 index 000000000000..c32bcd275c2f --- /dev/null +++ b/telecomm/java/android/telecomm/VideoCallImpl.java @@ -0,0 +1,245 @@ +/* + * 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 android.telecomm; + +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.telecomm.InCallService.VideoCall; +import android.view.Surface; + +import com.android.internal.os.SomeArgs; +import com.android.internal.telecomm.IVideoCallCallback; +import com.android.internal.telecomm.IVideoCallProvider; + +/** + * Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying + * {@link ConnectionService.VideoCallProvider}, and direct callbacks from the + * {@link ConnectionService.VideoCallProvider} to the appropriate {@link VideoCall.Listener}. + */ +public class VideoCallImpl extends VideoCall { + private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1; + private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2; + private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3; + private static final int MSG_CHANGE_PEER_DIMENSIONS = 4; + private static final int MSG_CHANGE_CALL_DATA_USAGE = 5; + private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6; + + private final IVideoCallProvider mVideoCallProvider; + private final VideoCallListenerBinder mBinder; + private VideoCall.Listener mVideoCallListener; + + private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + mVideoCallProvider.asBinder().unlinkToDeath(this, 0); + } + }; + + /** + * IVideoCallCallback stub implementation. + */ + private final class VideoCallListenerBinder extends IVideoCallCallback.Stub { + @Override + public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) { + mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST, + videoCallProfile).sendToTarget(); + } + + @Override + public void receiveSessionModifyResponse(int status, VideoCallProfile requestProfile, + VideoCallProfile responseProfile) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = status; + args.arg2 = requestProfile; + args.arg3 = responseProfile; + mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget(); + } + + @Override + public void handleCallSessionEvent(int event) { + mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget(); + } + + @Override + public void changePeerDimensions(int width, int height) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = width; + args.arg2 = height; + mHandler.obtainMessage(MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget(); + } + + @Override + public void changeCallDataUsage(int dataUsage) { + mHandler.obtainMessage(MSG_CHANGE_CALL_DATA_USAGE, dataUsage).sendToTarget(); + } + + @Override + public void changeCameraCapabilities(CallCameraCapabilities cameraCapabilities) { + mHandler.obtainMessage(MSG_CHANGE_CAMERA_CAPABILITIES, + cameraCapabilities).sendToTarget(); + } + } + + /** Default handler used to consolidate binder method calls onto a single thread. */ + private final Handler mHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + if (mVideoCallListener == null) { + return; + } + + SomeArgs args; + switch (msg.what) { + case MSG_RECEIVE_SESSION_MODIFY_REQUEST: + mVideoCallListener.onSessionModifyRequestReceived((VideoCallProfile) msg.obj); + break; + case MSG_RECEIVE_SESSION_MODIFY_RESPONSE: + args = (SomeArgs) msg.obj; + try { + int status = (int) args.arg1; + VideoCallProfile requestProfile = (VideoCallProfile) args.arg2; + VideoCallProfile responseProfile = (VideoCallProfile) args.arg3; + + mVideoCallListener.onSessionModifyResponseReceived( + status, requestProfile, responseProfile); + } finally { + args.recycle(); + } + break; + case MSG_HANDLE_CALL_SESSION_EVENT: + mVideoCallListener.onCallSessionEvent((int) msg.obj); + break; + case MSG_CHANGE_PEER_DIMENSIONS: + args = (SomeArgs) msg.obj; + try { + int width = (int) args.arg1; + int height = (int) args.arg2; + mVideoCallListener.onPeerDimensionsChanged(width, height); + } finally { + args.recycle(); + } + break; + case MSG_CHANGE_CALL_DATA_USAGE: + mVideoCallListener.onCallDataUsageChanged(msg.arg1); + break; + case MSG_CHANGE_CAMERA_CAPABILITIES: + mVideoCallListener.onCameraCapabilitiesChanged( + (CallCameraCapabilities) msg.obj); + break; + default: + break; + } + } + }; + + /** {@hide} */ + VideoCallImpl(IVideoCallProvider videoCallProvider) throws RemoteException { + mVideoCallProvider = videoCallProvider; + mVideoCallProvider.asBinder().linkToDeath(mDeathRecipient, 0); + + mBinder = new VideoCallListenerBinder(); + mVideoCallProvider.setVideoCallListener(mBinder); + } + + /** {@inheritDoc} */ + public void setVideoCallListener(VideoCall.Listener videoCallListener) { + mVideoCallListener = videoCallListener; + } + + /** {@inheritDoc} */ + public void setCamera(String cameraId) { + try { + mVideoCallProvider.setCamera(cameraId); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void setPreviewSurface(Surface surface) { + try { + mVideoCallProvider.setPreviewSurface(surface); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void setDisplaySurface(Surface surface) { + try { + mVideoCallProvider.setDisplaySurface(surface); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void setDeviceOrientation(int rotation) { + try { + mVideoCallProvider.setDeviceOrientation(rotation); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void setZoom(float value) { + try { + mVideoCallProvider.setZoom(value); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void sendSessionModifyRequest(VideoCallProfile requestProfile) { + try { + mVideoCallProvider.sendSessionModifyRequest(requestProfile); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void sendSessionModifyResponse(VideoCallProfile responseProfile) { + try { + mVideoCallProvider.sendSessionModifyResponse(responseProfile); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void requestCameraCapabilities() { + try { + mVideoCallProvider.requestCameraCapabilities(); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void requestCallDataUsage() { + try { + mVideoCallProvider.requestCallDataUsage(); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ + public void setPauseImage(String uri) { + try { + mVideoCallProvider.setPauseImage(uri); + } catch (RemoteException e) { + } + } +}
\ No newline at end of file diff --git a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl index 552993f3cd3b..60b5e1e892c6 100644 --- a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl +++ b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl @@ -22,7 +22,7 @@ import android.telecomm.ConnectionRequest; import android.telecomm.ParcelableConnection; import android.telecomm.StatusHints; -import com.android.internal.telecomm.ICallVideoProvider; +import com.android.internal.telecomm.IVideoCallProvider; import com.android.internal.telecomm.RemoteServiceCallback; /** @@ -65,7 +65,7 @@ oneway interface IConnectionServiceAdapter { void queryRemoteConnectionServices(RemoteServiceCallback callback); - void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider); + void setVideoCallProvider(String callId, IVideoCallProvider videoCallProvider); void setVideoState(String callId, int videoState); diff --git a/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl b/telecomm/java/com/android/internal/telecomm/IVideoCallCallback.aidl index 26895613c0f8..a71ab0af6ce4 100644 --- a/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl +++ b/telecomm/java/com/android/internal/telecomm/IVideoCallCallback.aidl @@ -20,25 +20,24 @@ import android.telecomm.CallCameraCapabilities; import android.telecomm.VideoCallProfile; /** - * Internal definition of the CallVideoClient, used for an InCall-UI to respond to video telephony - * related changes. + * Internal definition of the a callback interface, used for an InCallUi to respond to video + * telephony changes. * - * @see android.telecomm.CallVideoClient + * @see android.telecomm.InCallService.VideoCall.Listener * * {@hide} */ - oneway interface ICallVideoClient { +oneway interface IVideoCallCallback { + void receiveSessionModifyRequest(in VideoCallProfile videoCallProfile); - void receiveSessionModifyRequest(in VideoCallProfile videoCallProfile); + void receiveSessionModifyResponse(int status, in VideoCallProfile requestedProfile, + in VideoCallProfile responseProfile); - void receiveSessionModifyResponse(int status, in VideoCallProfile requestedProfile, - in VideoCallProfile responseProfile); + void handleCallSessionEvent(int event); - void handleCallSessionEvent(int event); + void changePeerDimensions(int width, int height); - void updatePeerDimensions(int width, int height); + void changeCallDataUsage(int dataUsage); - void updateCallDataUsage(int dataUsage); - - void handleCameraCapabilitiesChange(in CallCameraCapabilities callCameraCapabilities); - } + void changeCameraCapabilities(in CallCameraCapabilities callCameraCapabilities); +} diff --git a/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl b/telecomm/java/com/android/internal/telecomm/IVideoCallProvider.aidl index 860a4314bce6..c1ba74974c52 100644 --- a/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl +++ b/telecomm/java/com/android/internal/telecomm/IVideoCallProvider.aidl @@ -19,15 +19,13 @@ package com.android.internal.telecomm; import android.view.Surface; import android.telecomm.VideoCallProfile; -import com.android.internal.telecomm.ICallVideoClient; - /** - * Internal remote interface for a call video provider. - * @see android.telecomm.CallVideoProvider + * Internal remote interface for a video call provider. + * @see android.telecomm.VideoCallProvider * @hide */ -oneway interface ICallVideoProvider { - void setCallVideoClient(IBinder callVideoClient); +oneway interface IVideoCallProvider { + void setVideoCallListener(IBinder videoCallListenerBinder); void setCamera(String cameraId); diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index d2044be4dc0b..aa6c47c35df7 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -149,10 +149,21 @@ public class DisconnectCause { */ public static final int EXITED_ECM = 42; + /** + * The outgoing call failed with an unknown cause. + */ + public static final int OUTGOING_FAILURE = 43; + + /** + * The outgoing call was canceled by the {@link android.telecomm.ConnectionService}. + */ + public static final int OUTGOING_CANCELED = 44; + /** Smallest valid value for call disconnect codes. */ public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED; + /** Largest valid value for call disconnect codes. */ - public static final int MAXIMUM_VALID_VALUE = EXITED_ECM; + public static final int MAXIMUM_VALID_VALUE = OUTGOING_CANCELED; /** Private constructor to avoid class instantiation. */ private DisconnectCause() { @@ -246,6 +257,10 @@ public class DisconnectCause { return "EXITED_ECM"; case ERROR_UNSPECIFIED: return "ERROR_UNSPECIFIED"; + case OUTGOING_FAILURE: + return "OUTGOING_FAILURE"; + case OUTGOING_CANCELED: + return "OUTGOING_CANCELED"; default: return "INVALID"; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 39bbf72c0b21..35568cf95236 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -3322,4 +3322,23 @@ public class TelephonyManager { } return false; } + + /** + * Returns the result and response from RIL for oem request + * + * @param oemReq the data is sent to ril. + * @param oemResp the respose data from RIL. + * @return negative value request was not handled or get error + * 0 request was handled succesfully, but no response data + * positive value success, data length of response + * @hide + */ + public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) { + try { + return getITelephony().invokeOemRilRequestRaw(oemReq, oemResp); + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return -1; + } } diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl index 5f243a0fe63e..1413e58d87a4 100644 --- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl +++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl @@ -55,4 +55,15 @@ interface IImsRegistrationListener { * Else ({@code event} is 1), meaning the specified service is added to the IMS connection. */ void registrationServiceCapabilityChanged(int serviceClass, int event); + + /** + * Notifies the application when features on a particular service enabled or + * disabled successfully based on user preferences. + * + * @param serviceClass a service class specified in {@link ImsServiceClass} + * @param enabledFeatures features enabled as defined in com.android.ims.ImsConfig#FeatureConstants. + * @param disabledFeatures features disabled as defined in com.android.ims.ImsConfig#FeatureConstants. + */ + void registrationFeatureCapabilityChanged(int serviceClass, + out int[] enabledFeatures, out int[] disabledFeatures); } diff --git a/telephony/java/com/android/ims/internal/IImsService.aidl b/telephony/java/com/android/ims/internal/IImsService.aidl index d9921248d9b8..869cd9f2064b 100644 --- a/telephony/java/com/android/ims/internal/IImsService.aidl +++ b/telephony/java/com/android/ims/internal/IImsService.aidl @@ -51,4 +51,15 @@ interface IImsService { * Config interface to get/set IMS service/capability parameters. */ IImsConfig getConfigInterface(); + + /** + * Used for turning on IMS when its in OFF state. + */ + void turnOnIms(); + + /** + * Used for turning off IMS when its in ON state. + * When IMS is OFF, device will behave as CSFB'ed. + */ + void turnOffIms(); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 8c37e3d194db..886de400c1bd 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -737,5 +737,16 @@ interface ITelephony { * @return true if the operation was executed correctly. */ boolean setOperatorBrandOverride(String iccId, String brand); + + /** + * Returns the result and response from RIL for oem request + * + * @param oemReq the data is sent to ril. + * @param oemResp the respose data from RIL. + * @return negative value request was not handled or get error + * 0 request was handled succesfully, but no response data + * positive value success, data length of response + */ + int invokeOemRilRequestRaw(in byte[] oemReq, out byte[] oemResp); } diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 36c90f286d8c..8ce7888c4f67 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -750,7 +750,7 @@ public class MockPackageManager extends PackageManager { } /** {@hide} */ - public PackageInstaller getInstaller() { + public PackageInstaller getPackageInstaller() { throw new UnsupportedOperationException(); } diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java index f72e331c37a7..f4f610b1b280 100644 --- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java +++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java @@ -24,7 +24,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.PowerManager; -import android.service.dreams.DozeHardware; import android.service.dreams.DreamService; import android.text.format.DateFormat; import android.util.Log; @@ -49,10 +48,6 @@ public class DozeTestDream extends DreamService { // refreshed once the dream has finished rendering a new frame. private static final int UPDATE_TIME_TIMEOUT = 100; - // A doze hardware message string we use for end-to-end testing. - // Doesn't mean anything. Real hardware won't handle it. - private static final String TEST_PING_MESSAGE = "test.ping"; - // Not all hardware supports dozing. We should use Display.STATE_DOZE but // for testing purposes it is convenient to use Display.STATE_ON so the // test still works on hardware that does not support dozing. @@ -70,7 +65,6 @@ public class DozeTestDream extends DreamService { private java.text.DateFormat mTimeFormat; private boolean mDreaming; - private DozeHardware mDozeHardware; private long mLastTime = Long.MIN_VALUE; @@ -121,17 +115,11 @@ public class DozeTestDream extends DreamService { super.onDreamingStarted(); mDreaming = true; - mDozeHardware = getDozeHardware(); - Log.d(TAG, "Dream started: canDoze=" + canDoze() - + ", dozeHardware=" + mDozeHardware); + Log.d(TAG, "Dream started: canDoze=" + canDoze()); performTimeUpdate(); - if (mDozeHardware != null) { - mDozeHardware.sendMessage(TEST_PING_MESSAGE, null); - mDozeHardware.setEnableMcu(true); - } startDozing(); } @@ -140,10 +128,6 @@ public class DozeTestDream extends DreamService { super.onDreamingStopped(); mDreaming = false; - if (mDozeHardware != null) { - mDozeHardware.setEnableMcu(false); - mDozeHardware = null; - } Log.d(TAG, "Dream ended: isDozing=" + isDozing()); diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java index 397ef1318ef6..051ed0e17e08 100644 --- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java +++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java @@ -34,8 +34,10 @@ import android.util.Log; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * This test is intended to measure the amount of memory applications use when @@ -57,11 +59,12 @@ public class MemoryUsageTest extends InstrumentationTestCase { private static final String TAG = "MemoryUsageInstrumentation"; private static final String KEY_APPS = "apps"; - + private static final String KEY_PROCS = "persistent"; + private static final String LAUNCHER_KEY = "launcher"; private Map<String, Intent> mNameToIntent; private Map<String, String> mNameToProcess; private Map<String, String> mNameToResultKey; - + private Set<String> mPersistentProcesses; private IActivityManager mAm; public void testMemory() { @@ -75,35 +78,61 @@ public class MemoryUsageTest extends InstrumentationTestCase { Bundle results = new Bundle(); for (String app : mNameToResultKey.keySet()) { - String processName; - try { - processName = startApp(app); - measureMemory(app, processName, results); - closeApp(); - } catch (NameNotFoundException e) { - Log.i(TAG, "Application " + app + " not found"); + if (!mPersistentProcesses.contains(app)) { + String processName; + try { + processName = startApp(app); + measureMemory(app, processName, results); + closeApp(); + } catch (NameNotFoundException e) { + Log.i(TAG, "Application " + app + " not found"); + } + } else { + measureMemory(app, app, results); } - } instrumentation.sendStatus(0, results); } - private void parseArgs(Bundle args) { - mNameToResultKey = new HashMap<String, String>(); - String appList = args.getString(KEY_APPS); - - if (appList == null) - return; + private String getLauncherPackageName() { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + ResolveInfo resolveInfo = getInstrumentation().getContext(). + getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + return resolveInfo.activityInfo.packageName; + } - String appNames[] = appList.split("\\|"); - for (String pair : appNames) { + private Map<String, String> parseListToMap(String list) { + Map<String, String> map = new HashMap<String, String>(); + String names[] = list.split("\\|"); + for (String pair : names) { String[] parts = pair.split("\\^"); if (parts.length != 2) { Log.e(TAG, "The apps key is incorectly formatted"); fail(); } + map.put(parts[0], parts[1]); + } + return map; + } - mNameToResultKey.put(parts[0], parts[1]); + private void parseArgs(Bundle args) { + mNameToResultKey = new HashMap<String, String>(); + mPersistentProcesses = new HashSet<String>(); + String appList = args.getString(KEY_APPS); + String procList = args.getString(KEY_PROCS); + String mLauncherPackageName = getLauncherPackageName(); + mPersistentProcesses.add(mLauncherPackageName); + mNameToResultKey.put(mLauncherPackageName, LAUNCHER_KEY); + if (appList == null && procList == null) + return; + if (appList != null) { + mNameToResultKey.putAll(parseListToMap(appList)); + } + if (procList != null) { + Map<String, String> procMap = parseListToMap(procList); + mPersistentProcesses.addAll(procMap.keySet()); + mNameToResultKey.putAll(procMap); } } diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java index 0e7fe133d03d..937f1e6d6938 100644 --- a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java +++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java @@ -116,12 +116,12 @@ public class BrowserService extends MediaBrowserService { } @Override - protected BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { + public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { return new BrowserRoot(BROWSE_URI, null); } @Override - protected void onLoadChildren(final Uri parentUri, + public void onLoadChildren(final Uri parentUri, final Result<List<MediaBrowserItem>> result) { new Handler().postDelayed(new Runnable() { public void run() { @@ -142,7 +142,7 @@ public class BrowserService extends MediaBrowserService { } @Override - protected void onLoadThumbnail(Uri uri, int width, int height, Result<Bitmap> result) { + public void onLoadIcon(Uri uri, int width, int height, Result<Bitmap> result) { result.sendResult(null); } diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk new file mode 100644 index 000000000000..407a9d70d93f --- /dev/null +++ b/tests/SoundTriggerTests/Android.mk @@ -0,0 +1,27 @@ +# +# 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. +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := SoundTriggerTests + +include $(BUILD_PACKAGE) diff --git a/tests/SoundTriggerTests/AndroidManifest.xml b/tests/SoundTriggerTests/AndroidManifest.xml new file mode 100644 index 000000000000..5e5a108d263e --- /dev/null +++ b/tests/SoundTriggerTests/AndroidManifest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.hardware.soundtrigger"> + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="android.hardware.soundtrigger" + android:label="Tests for android.hardware.soundtrigger" /> +</manifest> diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java new file mode 100644 index 000000000000..5d32c66e42df --- /dev/null +++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java @@ -0,0 +1,256 @@ +/* + * 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 android.hardware.soundtrigger; + +import android.hardware.soundtrigger.SoundTrigger; +import android.hardware.soundtrigger.SoundTrigger.Keyphrase; +import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; +import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; +import android.os.Parcel; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; + +import java.util.Arrays; +import java.util.Random; +import java.util.UUID; + +public class SoundTriggerTest extends InstrumentationTestCase { + private Random mRandom = new Random(); + + @SmallTest + public void testKeyphraseParcelUnparcel_noUsers() throws Exception { + Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", null); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + keyphrase.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(keyphrase.id, unparceled.id); + assertNull(unparceled.users); + assertEquals(keyphrase.locale, unparceled.locale); + assertEquals(keyphrase.text, unparceled.text); + } + + @SmallTest + public void testKeyphraseParcelUnparcel_zeroUsers() throws Exception { + Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", new int[0]); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + keyphrase.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(keyphrase.id, unparceled.id); + assertTrue(Arrays.equals(keyphrase.users, unparceled.users)); + assertEquals(keyphrase.locale, unparceled.locale); + assertEquals(keyphrase.text, unparceled.text); + } + + @SmallTest + public void testKeyphraseParcelUnparcel_pos() throws Exception { + Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", new int[] {1, 2, 3, 4, 5}); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + keyphrase.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(keyphrase.id, unparceled.id); + assertTrue(Arrays.equals(keyphrase.users, unparceled.users)); + assertEquals(keyphrase.locale, unparceled.locale); + assertEquals(keyphrase.text, unparceled.text); + } + + @SmallTest + public void testKeyphraseSoundModelParcelUnparcel_noData() throws Exception { + Keyphrase[] keyphrases = new Keyphrase[2]; + keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0}); + keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), null, keyphrases); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertNull(unparceled.data); + assertEquals(ksm.type, unparceled.type); + assertTrue(Arrays.equals(keyphrases, unparceled.keyphrases)); + } + + @SmallTest + public void testKeyphraseSoundModelParcelUnparcel_zeroData() throws Exception { + Keyphrase[] keyphrases = new Keyphrase[2]; + keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0}); + keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), new byte[0], + keyphrases); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertEquals(ksm.type, unparceled.type); + assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases)); + assertTrue(Arrays.equals(ksm.data, unparceled.data)); + } + + @SmallTest + public void testKeyphraseSoundModelParcelUnparcel_noKeyphrases() throws Exception { + byte[] data = new byte[10]; + mRandom.nextBytes(data); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data, null); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertEquals(ksm.type, unparceled.type); + assertNull(unparceled.keyphrases); + assertTrue(Arrays.equals(ksm.data, unparceled.data)); + } + + @SmallTest + public void testKeyphraseSoundModelParcelUnparcel_zeroKeyphrases() throws Exception { + byte[] data = new byte[10]; + mRandom.nextBytes(data); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data, + new Keyphrase[0]); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertEquals(ksm.type, unparceled.type); + assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases)); + assertTrue(Arrays.equals(ksm.data, unparceled.data)); + } + + @LargeTest + public void testKeyphraseSoundModelParcelUnparcel_largeData() throws Exception { + Keyphrase[] keyphrases = new Keyphrase[2]; + keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0}); + keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); + byte[] data = new byte[200 * 1024]; + mRandom.nextBytes(data); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data, keyphrases); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertEquals(ksm.type, unparceled.type); + assertTrue(Arrays.equals(ksm.data, unparceled.data)); + assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases)); + } + + @SmallTest + public void testRecognitionEventParcelUnparcel_noData() throws Exception { + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1, + true, 2, 3, 4, null); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @SmallTest + public void testRecognitionEventParcelUnparcel_zeroData() throws Exception { + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, + true, 2, 3, 4, new byte[1]); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @SmallTest + public void testRecognitionEventParcelUnparcel_largeData() throws Exception { + byte[] data = new byte[200 * 1024]; + mRandom.nextBytes(data); + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1, + false, 2, 3, 4, data); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } +} diff --git a/tests/UsesFeature2Test/Android.mk b/tests/UsesFeature2Test/Android.mk new file mode 100644 index 000000000000..cc784d7944aa --- /dev/null +++ b/tests/UsesFeature2Test/Android.mk @@ -0,0 +1,25 @@ +# +# 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_PACKAGE_NAME := UsesFeature2Test + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/UsesFeature2Test/AndroidManifest.xml b/tests/UsesFeature2Test/AndroidManifest.xml new file mode 100644 index 000000000000..724d1861bf11 --- /dev/null +++ b/tests/UsesFeature2Test/AndroidManifest.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.usesfeature2"> + + <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" /> + + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> + <uses-permission android:name="android.permission.BLUETOOTH" /> + + <uses-feature android:name="android.hardware.sensor.accelerometer" /> + <feature-group android:label="@string/minimal"> + <uses-feature android:name="android.hardware.dpad" /> + <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" /> + </feature-group> + <feature-group android:label="@string/gamepad"> + <uses-feature android:name="android.hardware.gamepad" /> + </feature-group> + + <application android:label="@string/app_title"> + <activity android:name="ActivityMain"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/UsesFeature2Test/res/values/values.xml b/tests/UsesFeature2Test/res/values/values.xml new file mode 100644 index 000000000000..2ee91072e6f2 --- /dev/null +++ b/tests/UsesFeature2Test/res/values/values.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_title">Uses Feature 2.0</string> + <string name="minimal">Crippled experience</string> + <string name="gamepad">Gamer experience</string> +</resources> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml index 3b01e029e1c7..705cc34ff62b 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml @@ -13,22 +13,18 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android"> - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" - android:width="48dp" /> - - <viewport + android:width="48dp" android:viewportHeight="480" - android:viewportWidth="480" /> + android:viewportWidth="480" > <group> <path android:name="box1" android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z" - android:fill="?android:attr/colorControlActivated" - android:stroke="?android:attr/colorControlActivated" + android:fillColor="?android:attr/colorControlActivated" + android:strokeColor="?android:attr/colorControlActivated" android:strokeLineCap="round" android:strokeLineJoin="round" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml index 40f23f0c4bc1..f5d647ceaa8f 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml @@ -12,14 +12,10 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport android:viewportWidth="320" - android:viewportHeight="320"/> + android:height="64dp" android:viewportWidth="320" + android:viewportHeight="320"> <group android:rotation="180" android:pivotX="70" @@ -27,8 +23,8 @@ <path android:name="house" android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z" - android:fill="#ff440000" - android:stroke="#FF00FF00" + android:fillColor="#ff440000" + android:strokeColor="#FF00FF00" android:strokeWidth="10" android:trimPathStart=".1" android:trimPathEnd=".9"/> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml index cd2fd479098d..a0b0e000d09e 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml @@ -14,23 +14,17 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" > - - <size android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="12.25" - android:viewportWidth="7.30625" /> + android:viewportWidth="7.30625" > <group android:pivotX="3.65" android:pivotY="6.125" android:rotation="-30" > - <path + <clip-path android:name="clip1" - android:clipToPath="true" android:pathData=" M 0, 6.125 l 7.3, 0 @@ -41,7 +35,7 @@ <group> <path android:name="one" - android:fill="#ff88ff" + android:fillColor="#ff88ff" android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 l-5.046875,0.0 0.0-1.0Z" /> @@ -50,9 +44,8 @@ android:pivotX="3.65" android:pivotY="6.125" android:rotation="-30" > - <path + <clip-path android:name="clip2" - android:clipToPath="true" android:pathData=" M 0, 0 l 7.3, 0 @@ -63,7 +56,7 @@ <group> <path android:name="two" - android:fill="#ff88ff" + android:fillColor="#ff88ff" android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml index d57ae8b756ef..5a7f380bda1d 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml @@ -13,45 +13,33 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true"> - - <size android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="7.30625" - android:viewportHeight="12.25"/> + android:viewportHeight="12.25"> <group> - <path + <clip-path android:name="clip1" android:pathData=" M 3.65, 6.125 m-.001, 0 a .001,.001 0 1,0 .002,0 - a .001,.001 0 1,0-.002,0z" - android:clipToPath="true" - android:fill="#112233" - /> - + a .001,.001 0 1,0-.002,0z"/> <path android:name="one" android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 l-5.046875,0.0 0.0-1.0Z" - android:fill="#ff88ff" - /> - <path + android:fillColor="#ff88ff"/> + + <clip-path android:name="clip2" android:pathData=" M 3.65, 6.125 m-6, 0 a 6,6 0 1,0 12,0 - a 6,6 0 1,0-12,0z" - android:clipToPath="true" - android:fill="#112233" - /> + a 6,6 0 1,0-12,0z"/> <path android:name="two" android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 @@ -63,7 +51,6 @@ q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 q-0.78125024,0.8125-2.2187502,2.265625Z" - android:fill="#ff88ff" - /> + android:fillColor="#ff88ff"/> </group> </vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml index 673c46524243..5b1f6abba3d3 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml @@ -14,26 +14,21 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true"> - - <size android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="12.25" - android:viewportWidth="7.30625" /> + android:viewportWidth="7.30625" > <group> <path android:name="one" - android:fill="#ffff00" + android:fillColor="#ffff00" android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 l-5.046875,0.0 0.0-1.0Z" /> <path android:name="two" - android:fill="#ffff00" + android:fillColor="#ffff00" android:fillOpacity="0" android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml index ab5f7f49ba3a..98b623572eb7 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml @@ -12,41 +12,37 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport + android:height="64dp" android:viewportWidth="700" - android:viewportHeight="700"/> + android:viewportHeight="700"> <group> <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z" android:name="path2451" - android:fill="#00000000" - android:stroke="#FF000000" + android:fillColor="#00000000" + android:strokeColor="#FF000000" android:strokeWidth="30.65500000000000"/> <path android:pathData="M 365.015 311.066" android:name="path2453" - android:fill="#00000000" - android:stroke="#FF000000" + android:fillColor="#00000000" + android:strokeColor="#FF000000" android:strokeWidth="30.655000000000001"/> <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928" android:name="path2455" - android:stroke="#FF000000" - android:fill="#FFFFFFFF" + android:strokeColor="#FF000000" + android:fillColor="#FFFFFFFF" android:strokeWidth="30.655000000000001"/> <path android:pathData="M 170.515 451.566L 305.61 313.46" android:name="path2457" - android:fill="#00000000" - android:stroke="#000000" + android:fillColor="#00000000" + android:strokeColor="#000000" android:strokeWidth="30.655000000000001"/> <path android:pathData="M 557.968 449.974L 426.515 315.375" android:name="path2459" - android:fill="#00000000" - android:stroke="#000000" + android:fillColor="#00000000" + android:strokeColor="#000000" android:strokeWidth="30.655000000000001"/> </group> </vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml index ccb0df0c9aa8..88c4a1eaea48 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml @@ -12,13 +12,10 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport android:viewportWidth="140" - android:viewportHeight="110"/> + android:height="64dp" android:viewportWidth="140" + android:viewportHeight="110"> <group> <path @@ -26,7 +23,7 @@ android:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z M 27,50 l 97,0 0,10-97,0 z M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z" - android:fill="#ffffffff" + android:fillColor="#ffffffff" /> </group> </vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml index 59f745942dc7..75529e2fd4ed 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml @@ -12,22 +12,17 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - - <viewport android:viewportWidth="600" - android:viewportHeight="600"/> + android:height="64dp" android:viewportWidth="600" + android:viewportHeight="600"> <group> <path android:name="pie1" android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z" - android:fill="#ffffcc00" - android:stroke="#FF00FF00" + android:fillColor="#ffffcc00" + android:strokeColor="#FF00FF00" android:strokeWidth="1"/> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml index 77434fca58f0..853a77000d4c 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="200" - android:viewportWidth="200" /> + android:viewportWidth="200" > <group android:pivotX="100" @@ -29,7 +25,7 @@ android:rotation="90"> <path android:name="house" - android:fill="#ffffffff" + android:fillColor="#ffffffff" android:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml index df24713e3ba0..83ed194a14e4 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml @@ -14,32 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportWidth="200" - android:viewportHeight="200"/> + android:viewportHeight="200"> <group> <path android:name="bar3" - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" /> <path android:name="bar2" - android:fill="#FFFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" /> <path android:name="bar1" - android:fill="#FF555555" + android:fillColor="#FF555555" android:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" /> <path android:name="bar0" - android:fill="#FF555555" + android:fillColor="#FF555555" android:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml index 3422bbfe9d05..b3d7d8eed349 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml @@ -13,26 +13,22 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="80" - android:viewportWidth="40" /> + android:viewportWidth="40" > <group> <path android:name="battery" - android:fill="#3388ff" + android:fillColor="#3388ff" android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z" - android:stroke="#ff8833" + android:strokeColor="#ff8833" android:strokeWidth="1" /> <path android:name="spark" - android:fill="#FFFF0000" + android:fillColor="#FFFF0000" android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml index a212defb551c..2c8b75118dfe 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="600" - android:viewportWidth="600" /> + android:viewportWidth="600" > <group android:name="rotationGroup" @@ -30,16 +26,16 @@ android:rotation="45.0" > <path android:name="pie1" - android:fill="#00000000" + android:fillColor="#00000000" android:pathData="M300,70 a230,230 0 1,0 1,0 z" - android:stroke="#FF777777" + android:strokeColor="#FF777777" android:strokeWidth="70" android:trimPathEnd=".75" android:trimPathOffset="0" android:trimPathStart="0" /> <path android:name="v" - android:fill="#000000" + android:fillColor="#000000" android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> <group @@ -55,7 +51,7 @@ <path android:name="twoLines1" android:pathData="@string/twoLinePathData" - android:stroke="#FFFF0000" + android:strokeColor="#FFFF0000" android:strokeWidth="20" /> <group @@ -69,9 +65,9 @@ android:rotation="-45.0" > <path android:name="twoLines2" - android:fill="#FF00FF00" + android:fillColor="#FF00FF00" android:pathData="@string/twoLinePathData" - android:stroke="#FF00FF00" + android:strokeColor="#FF00FF00" android:strokeWidth="20" /> <group @@ -86,7 +82,7 @@ <path android:name="twoLines3" android:pathData="@string/twoLinePathData" - android:stroke="#FF0000FF" + android:strokeColor="#FF0000FF" android:strokeWidth="20" /> </group> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml index 8c946df20d5e..2468a1b303cb 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml @@ -13,28 +13,24 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="400" - android:viewportWidth="600" /> + android:viewportWidth="600" > <group> <path android:name="pie1" - android:fill="#ffffffff" + android:fillColor="#ffffffff" android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z" - android:stroke="#FF00FF00" + android:strokeColor="#FF00FF00" android:strokeWidth="1" /> <path android:name="half" - android:fill="#FFFF0000" + android:fillColor="#FFFF0000" android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z" - android:stroke="#FF0000FF" + android:strokeColor="#FF0000FF" android:strokeWidth="5" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml index 8d4ca61f82ab..01e24d302288 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="500" - android:viewportWidth="800" /> + android:viewportWidth="800" > <group android:pivotX="90" @@ -34,8 +30,8 @@ a25,25 -30 0,1 100,-50 l 50,-25 a25,37 -30 0,1 100,-50 l 50,-25 a25,50 -30 0,1 100,-50 l 50,-25" - android:fill="#00000000" - android:stroke="#FF00FF00" + android:fillColor="#00000000" + android:strokeColor="#FF00FF00" android:strokeWidth="10" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml index b08e157f00ca..4bab2e37898a 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="400" - android:viewportWidth="500" /> + android:viewportWidth="500" > <group android:pivotX="250" @@ -29,9 +25,9 @@ android:rotation="180"> <path android:name="house" - android:fill="#ff440000" + android:fillColor="#ff440000" android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200" - android:stroke="#FFFF0000" + android:strokeColor="#FFFF0000" android:strokeWidth="10" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml index ae85d9b14caa..107cda2ca233 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml @@ -13,25 +13,21 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="200" - android:viewportWidth="200" /> + android:viewportWidth="200" > <group> <path android:name="background1" android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" - android:fill="#FF000000"/> + android:fillColor="#FF000000"/> <path android:name="background2" android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" - android:fill="#FF000000"/> + android:fillColor="#FF000000"/> </group> <group android:pivotX="100" @@ -44,7 +40,7 @@ <path android:name="twoLines" android:pathData="M 100,10 v 90 M 10,100 h 90" - android:stroke="#FF00FF00" + android:strokeColor="#FF00FF00" android:strokeWidth="10" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml index c28aff46cd89..801954986ab7 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml @@ -12,21 +12,17 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" - android:height="64dp"/> - - <viewport android:viewportWidth="1200" - android:viewportHeight="600"/> + android:height="64dp" android:viewportWidth="1200" + android:viewportHeight="600"> <group> <path android:name="house" android:pathData="M200,300 Q400,50 600,300 T1000,300" - android:fill="#00000000" - android:stroke="#FFFF0000" + android:fillColor="#00000000" + android:strokeColor="#FFFF0000" android:strokeWidth="10"/> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml index d7042fd0b2ba..c93bdb94f646 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml @@ -13,22 +13,18 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="400" - android:viewportWidth="500" /> + android:viewportWidth="500" > <group> <path android:name="house" android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200" - android:fill="#00000000" - android:stroke="#FFFFFF00" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF00" android:strokeWidth="10" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml index 47a9574eb681..996b6beff8bf 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="800" - android:viewportWidth="1000" /> + android:viewportWidth="1000" > <group> <path @@ -29,8 +25,8 @@ android:pathData="M10,300 Q400,550 600,300 T1000,300" android:pivotX="90" android:pivotY="100" - android:fill="#00000000" - android:stroke="#FFFF0000" + android:fillColor="#00000000" + android:strokeColor="#FFFF0000" android:strokeWidth="60" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml index b8af7e2d076c..58021446bdc5 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml @@ -13,25 +13,21 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="480" - android:viewportWidth="480" /> + android:viewportWidth="480" > <group> <path android:name="edit" - android:fill="#FF00FFFF" + android:fillColor="#FF00FFFF" android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333 c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40 c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522 c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z" - android:stroke="#FF000000" + android:strokeColor="#FF000000" android:strokeWidth="10" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml index e0013e7d28dd..5626b44e4b50 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml @@ -13,25 +13,21 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="200" - android:viewportWidth="200" /> + android:viewportWidth="200" > <group> <path android:name="background1" android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" - android:fill="#FF000000"/> + android:fillColor="#FF000000"/> <path android:name="background2" android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" - android:fill="#FF000000"/> + android:fillColor="#FF000000"/> </group> <group android:pivotX="0" @@ -44,7 +40,7 @@ <path android:name="twoLines" android:pathData="M 100,10 v 90 M 10,100 h 90" - android:stroke="#FF00FF00" + android:strokeColor="#FF00FF00" android:strokeWidth="10" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml index 8d38cb51bf42..5b40d0d07013 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml @@ -13,24 +13,20 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="400" - android:viewportWidth="400" /> + android:viewportWidth="400" > <group android:name="backgroundGroup" > <path android:name="background1" - android:fill="#80000000" + android:fillColor="#80000000" android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> <path android:name="background2" - android:fill="#80000000" + android:fillColor="#80000000" android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> </group> <group @@ -40,7 +36,7 @@ <path android:name="twoLines" android:pathData="M 0,0 v 100 M 0,0 h 100" - android:stroke="#FFFF0000" + android:strokeColor="#FFFF0000" android:strokeWidth="20" /> <group @@ -51,7 +47,7 @@ <path android:name="twoLines1" android:pathData="M 0,0 v 100 M 0,0 h 100" - android:stroke="#FF00FF00" + android:strokeColor="#FF00FF00" android:strokeWidth="20" /> <group @@ -62,7 +58,7 @@ <path android:name="twoLines2" android:pathData="M 0,0 v 100 M 0,0 h 100" - android:stroke="#FF0000FF" + android:strokeColor="#FF0000FF" android:strokeWidth="20" /> </group> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml index 52acd7afed5a..6ab6ffd2b1fb 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml @@ -13,24 +13,20 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="400" - android:viewportWidth="400" /> + android:viewportWidth="400" > <group android:name="backgroundGroup" > <path android:name="background1" - android:fill="#80000000" + android:fillColor="#80000000" android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> <path android:name="background2" - android:fill="#80000000" + android:fillColor="#80000000" android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> </group> <group @@ -40,7 +36,7 @@ <path android:name="twoLines" android:pathData="@string/twoLinePathData" - android:stroke="#FFFF0000" + android:strokeColor="#FFFF0000" android:strokeWidth="20" /> <group @@ -51,7 +47,7 @@ <path android:name="twoLines1" android:pathData="@string/twoLinePathData" - android:stroke="#FF00FF00" + android:strokeColor="#FF00FF00" android:strokeWidth="20" /> <group @@ -62,7 +58,7 @@ <path android:name="twoLines3" android:pathData="@string/twoLinePathData" - android:stroke="#FF0000FF" + android:strokeColor="#FF0000FF" android:strokeWidth="20" /> </group> </group> @@ -75,8 +71,8 @@ <path android:name="twoLines2" android:pathData="@string/twoLinePathData" - android:fill="?android:attr/colorForeground" - android:stroke="?android:attr/colorForeground" + android:fillColor="?android:attr/colorForeground" + android:strokeColor="?android:attr/colorForeground" android:strokeWidth="20" /> </group> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml index c062d702f0d8..5c1ccaa03361 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml @@ -13,25 +13,21 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="400" - android:viewportWidth="400" /> + android:viewportWidth="400" > <group android:name="backgroundGroup" android:alpha = "0.5" > <path android:name="background1" - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> <path android:name="background2" - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> </group> <group @@ -42,7 +38,7 @@ <path android:name="twoLines" android:pathData="@string/twoLinePathData" - android:stroke="#FFFF0000" + android:strokeColor="#FFFF0000" android:strokeWidth="20" /> <group @@ -54,7 +50,7 @@ <path android:name="twoLines1" android:pathData="@string/twoLinePathData" - android:stroke="#FF00FF00" + android:strokeColor="#FF00FF00" android:strokeWidth="20" /> <group @@ -66,7 +62,7 @@ <path android:name="twoLines3" android:pathData="@string/twoLinePathData" - android:stroke="#FF0000FF" + android:strokeColor="#FF0000FF" android:strokeWidth="20" /> </group> </group> @@ -80,8 +76,8 @@ <path android:name="twoLines2" android:pathData="@string/twoLinePathData" - android:fill="?android:attr/colorForeground" - android:stroke="?android:attr/colorForeground" + android:fillColor="?android:attr/colorForeground" + android:strokeColor="?android:attr/colorForeground" android:strokeWidth="20" /> </group> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml index a3f044787598..069a53154495 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="400" - android:viewportWidth="400" /> + android:viewportWidth="400" > <group android:name="FirstLevelGroup" @@ -34,7 +30,7 @@ android:translateX="-100.0" android:translateY="50.0" > <path - android:fill="#FF00FF00" + android:fillColor="#FF00FF00" android:pathData="@string/rectangle200" /> <group @@ -43,7 +39,7 @@ android:translateX="-100.0" android:translateY="50.0" > <path - android:fill="#FF0000FF" + android:fillColor="#FF0000FF" android:pathData="@string/rectangle200" /> </group> <group @@ -52,7 +48,7 @@ android:translateX="100.0" android:translateY="50.0" > <path - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="@string/rectangle200" /> </group> </group> @@ -62,7 +58,7 @@ android:translateX="100.0" android:translateY="50.0" > <path - android:fill="#FF0000FF" + android:fillColor="#FF0000FF" android:pathData="@string/rectangle200" /> <group @@ -71,7 +67,7 @@ android:translateX="-100.0" android:translateY="50.0" > <path - android:fill="#FFFF0000" + android:fillColor="#FFFF0000" android:pathData="@string/rectangle200" /> </group> <group @@ -80,13 +76,13 @@ android:translateX="100.0" android:translateY="50.0" > <path - android:fill="#FF00FF00" + android:fillColor="#FF00FF00" android:pathData="@string/rectangle200" /> </group> </group> <path - android:fill="#FFFF0000" + android:fillColor="#FFFF0000" android:pathData="@string/rectangle200" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml index 5a66e2d4bc9f..7be49a9d9b86 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="128dp" - android:width="128dp" /> - - <viewport + android:width="128dp" android:viewportHeight="480" - android:viewportWidth="480" /> + android:viewportWidth="480" > <group android:name="root" @@ -29,7 +25,7 @@ android:translateY="240.0" > <path android:name="favorite" - android:fill="#ff000000" + android:fillColor="#ff000000" android:pathData="M2.100006104,-6 C0.1449127197,-6,1.600006104,-5.975006104,0,-5.975006104 C-1.574996948,-5.975006104,0.00309753418,-6-1.949996948-6 diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml index 558de94375a0..7839ad19d0f1 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="256" - android:viewportWidth="256" /> + android:viewportWidth="256" > <group android:name="shape_layer_1" @@ -30,7 +26,7 @@ <group android:name="sun" > <path android:name="ellipse_path_1" - android:fill="#ffff8000" + android:fillColor="#ffff8000" android:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" /> <group @@ -38,7 +34,7 @@ android:translateX="75" > <path android:name="ellipse_path_1_1" - android:fill="#ff5656ea" + android:fillColor="#ff5656ea" android:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" /> <group @@ -46,7 +42,7 @@ android:translateX="25" > <path android:name="ellipse_path_1_2" - android:fill="#ffadadad" + android:fillColor="#ffadadad" android:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" /> </group> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml index f1b2996beab2..4544cae92a31 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml @@ -13,15 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="64" - android:viewportWidth="64" /> + android:viewportWidth="64" > <group android:name="root" @@ -37,9 +33,9 @@ android:rotation="0" > <path android:name="pie1" - android:fill="#00000000" + android:fillColor="#00000000" android:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19" - android:stroke="?android:attr/colorControlActivated" + android:strokeColor="?android:attr/colorControlActivated" android:strokeLineCap="round" android:strokeLineJoin="miter" android:strokeWidth="2" diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml index 22ce795564fc..0a6cedc5ced1 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml @@ -13,19 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="24" - android:viewportWidth="24" /> + android:viewportWidth="24" > <group> <path - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml index 042173ca9f9c..94c10dfd6656 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml @@ -13,19 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="24" - android:viewportWidth="24" /> + android:viewportWidth="24" > <group> <path - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml index 6b6f43de122b..870e508319e2 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml @@ -13,19 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="24" - android:viewportWidth="24" /> + android:viewportWidth="24" > <group> <path - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml index ba8ebcad170c..8cabca86368f 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml @@ -13,15 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="24" - android:viewportWidth="24" /> + android:viewportWidth="24" > <group> <path diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml index 896a9387afe6..7bd6304f78e4 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml @@ -13,19 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" - android:width="64dp" /> - - <viewport + android:width="64dp" android:viewportHeight="24" - android:viewportWidth="24" /> + android:viewportWidth="24" > <group> <path - android:fill="#FF000000" + android:fillColor="#FF000000" android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml index fc2a15c11b23..dd71ef0e88f5 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_test01.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_test01.xml @@ -13,23 +13,19 @@ 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" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="128dp" - android:width="128dp" /> - - <viewport + android:width="128dp" android:viewportHeight="512" - android:viewportWidth="512" /> + android:viewportWidth="512" > <group> <path android:name="002b" android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299" - android:stroke="#FF0000FF" + android:strokeColor="#FF0000FF" android:strokeWidth="4" - android:fill="#00000000" /> + android:fillColor="#00000000" /> </group> </vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_test02.xml b/tests/VectorDrawableTest/res/drawable/vector_test02.xml index 9f4abbff5d91..e4f48de862fa 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_test02.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_test02.xml @@ -13,23 +13,19 @@ 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" > - - <size +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="128dp" - android:width="128dp" /> - - <viewport + android:width="128dp" android:viewportHeight="512" - android:viewportWidth="512" /> + android:viewportWidth="512" > <group> <path android:name="002b" android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299" - android:stroke="#FF0000FF" + android:strokeColor="#FF0000FF" android:strokeWidth="4" - android:fill="#00000000" /> + android:fillColor="#00000000" /> </group> </vector>
\ No newline at end of file diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index 5fefab66b331..ac1ae70b2309 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -4,20 +4,23 @@ // Android Asset Packaging Tool main entry point. // #include "ApkBuilder.h" -#include "Main.h" #include "Bundle.h" +#include "Images.h" +#include "Main.h" #include "ResourceFilter.h" #include "ResourceTable.h" -#include "Images.h" #include "XMLNode.h" +#include <utils/Errors.h> +#include <utils/KeyedVector.h> +#include <utils/List.h> #include <utils/Log.h> +#include <utils/SortedVector.h> #include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> +#include <utils/Vector.h> -#include <fcntl.h> #include <errno.h> +#include <fcntl.h> using namespace android; @@ -588,6 +591,106 @@ static void printComponentPresence(const char* componentName) { printf("provides-component:'%s'\n", componentName); } +/** + * Represents a feature that has been automatically added due to + * a pre-requisite or some other reason. + */ +struct ImpliedFeature { + /** + * Name of the implied feature. + */ + String8 name; + + /** + * List of human-readable reasons for why this feature was implied. + */ + SortedVector<String8> reasons; +}; + +/** + * Represents a <feature-group> tag in the AndroidManifest.xml + */ +struct FeatureGroup { + /** + * Human readable label + */ + String8 label; + + /** + * Explicit features defined in the group + */ + KeyedVector<String8, bool> features; +}; + +static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures, + const char* name, const char* reason) { + String8 name8(name); + ssize_t idx = impliedFeatures->indexOfKey(name8); + if (idx < 0) { + idx = impliedFeatures->add(name8, ImpliedFeature()); + impliedFeatures->editValueAt(idx).name = name8; + } + impliedFeatures->editValueAt(idx).reasons.add(String8(reason)); +} + +static void printFeatureGroup(const FeatureGroup& grp, + const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) { + printf("feature-group: label='%s'\n", grp.label.string()); + + const size_t numFeatures = grp.features.size(); + for (size_t i = 0; i < numFeatures; i++) { + if (!grp.features[i]) { + continue; + } + + const String8& featureName = grp.features.keyAt(i); + printf(" uses-feature: name='%s'\n", + ResTable::normalizeForOutput(featureName.string()).string()); + } + + const size_t numImpliedFeatures = + (impliedFeatures != NULL) ? impliedFeatures->size() : 0; + for (size_t i = 0; i < numImpliedFeatures; i++) { + const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i); + if (grp.features.indexOfKey(impliedFeature.name) >= 0) { + // The feature is explicitly set, no need to use implied + // definition. + continue; + } + + String8 printableFeatureName(ResTable::normalizeForOutput( + impliedFeature.name.string())); + printf(" uses-feature: name='%s'\n", printableFeatureName.string()); + printf(" uses-implied-feature: name='%s' reason='", + printableFeatureName.string()); + const size_t numReasons = impliedFeature.reasons.size(); + for (size_t j = 0; j < numReasons; j++) { + printf("%s", impliedFeature.reasons[j].string()); + if (j + 2 < numReasons) { + printf(", "); + } else if (j + 1 < numReasons) { + printf(", and "); + } + } + printf("'\n"); + } +} + +static void addParentFeatures(FeatureGroup* grp, const String8& name) { + if (name == "android.hardware.camera.autofocus" || + name == "android.hardware.camera.flash") { + grp->features.add(String8("android.hardware.camera"), true); + } else if (name == "android.hardware.location.gps" || + name == "android.hardware.location.network") { + grp->features.add(String8("android.hardware.location"), true); + } else if (name == "android.hardware.touchscreen.multitouch") { + grp->features.add(String8("android.hardware.touchscreen"), true); + } else if (name == "android.hardware.touchscreen.multitouch.distinct") { + grp->features.add(String8("android.hardware.touchscreen.multitouch"), true); + grp->features.add(String8("android.hardware.touchscreen"), true); + } +} + /* * Handle the "dump" command, to extract select data from an archive. */ @@ -797,6 +900,7 @@ int doDump(Bundle* bundle) bool isSearchable = false; bool withinApplication = false; bool withinSupportsInput = false; + bool withinFeatureGroup = false; bool withinReceiver = false; bool withinService = false; bool withinProvider = false; @@ -869,36 +973,7 @@ int doDump(Bundle* bundle) // some new uses-feature constants in 2.1 and 2.2. In most cases, the // heuristic is "if an app requests a permission but doesn't explicitly // request the corresponding <uses-feature>, presume it's there anyway". - bool specCameraFeature = false; // camera-related - bool specCameraAutofocusFeature = false; - bool reqCameraAutofocusFeature = false; - bool reqCameraFlashFeature = false; - bool hasCameraPermission = false; - bool specLocationFeature = false; // location-related - bool specNetworkLocFeature = false; - bool reqNetworkLocFeature = false; - bool specGpsFeature = false; - bool reqGpsFeature = false; - bool hasMockLocPermission = false; - bool hasCoarseLocPermission = false; - bool hasGpsPermission = false; - bool hasGeneralLocPermission = false; - bool specBluetoothFeature = false; // Bluetooth API-related - bool hasBluetoothPermission = false; - bool specMicrophoneFeature = false; // microphone-related - bool hasRecordAudioPermission = false; - bool specWiFiFeature = false; - bool hasWiFiPermission = false; - bool specTelephonyFeature = false; // telephony-related - bool reqTelephonySubFeature = false; - bool hasTelephonyPermission = false; - bool specTouchscreenFeature = false; // touchscreen-related - bool specMultitouchFeature = false; - bool reqDistinctMultitouchFeature = false; - bool specScreenPortraitFeature = false; - bool specScreenLandscapeFeature = false; - bool reqScreenPortraitFeature = false; - bool reqScreenLandscapeFeature = false; + // 2.2 also added some other features that apps can request, but that // have no corresponding permission, so we cannot implement any // back-compatibility heuristic for them. The below are thus unnecessary @@ -926,6 +1001,11 @@ int doDump(Bundle* bundle) String8 receiverName; String8 serviceName; Vector<String8> supportedInput; + + FeatureGroup commonFeatures; + Vector<FeatureGroup> featureGroups; + KeyedVector<String8, ImpliedFeature> impliedFeatures; + while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::END_TAG) { depth--; @@ -946,6 +1026,7 @@ int doDump(Bundle* bundle) } withinApplication = false; withinSupportsInput = false; + withinFeatureGroup = false; } else if (depth < 3) { if (withinActivity && isMainActivity) { String8 aName(getComponentName(pkg, activityName)); @@ -1210,59 +1291,27 @@ int doDump(Bundle* bundle) COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0); largestWidthLimitDp = getIntegerAttribute(tree, LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0); + } else if (tag == "feature-group") { + withinFeatureGroup = true; + FeatureGroup group; + group.label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); + if (error != "") { + fprintf(stderr, "ERROR getting 'android:label' attribute:" + " %s\n", error.string()); + goto bail; + } + featureGroups.add(group); + } else if (tag == "uses-feature") { String8 name = getAttribute(tree, NAME_ATTR, &error); - if (name != "" && error == "") { int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1); - if (name == "android.hardware.camera") { - specCameraFeature = true; - } else if (name == "android.hardware.camera.autofocus") { - // these have no corresponding permission to check for, - // but should imply the foundational camera permission - reqCameraAutofocusFeature = reqCameraAutofocusFeature || req; - specCameraAutofocusFeature = true; - } else if (req && (name == "android.hardware.camera.flash")) { - // these have no corresponding permission to check for, - // but should imply the foundational camera permission - reqCameraFlashFeature = true; - } else if (name == "android.hardware.location") { - specLocationFeature = true; - } else if (name == "android.hardware.location.network") { - specNetworkLocFeature = true; - reqNetworkLocFeature = reqNetworkLocFeature || req; - } else if (name == "android.hardware.location.gps") { - specGpsFeature = true; - reqGpsFeature = reqGpsFeature || req; - } else if (name == "android.hardware.bluetooth") { - specBluetoothFeature = true; - } else if (name == "android.hardware.touchscreen") { - specTouchscreenFeature = true; - } else if (name == "android.hardware.touchscreen.multitouch") { - specMultitouchFeature = true; - } else if (name == "android.hardware.touchscreen.multitouch.distinct") { - reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req; - } else if (name == "android.hardware.microphone") { - specMicrophoneFeature = true; - } else if (name == "android.hardware.wifi") { - specWiFiFeature = true; - } else if (name == "android.hardware.telephony") { - specTelephonyFeature = true; - } else if (req && (name == "android.hardware.telephony.gsm" || - name == "android.hardware.telephony.cdma")) { - // these have no corresponding permission to check for, - // but should imply the foundational telephony permission - reqTelephonySubFeature = true; - } else if (name == "android.hardware.screen.portrait") { - specScreenPortraitFeature = true; - } else if (name == "android.hardware.screen.landscape") { - specScreenLandscapeFeature = true; + commonFeatures.features.add(name, req); + if (req) { + addParentFeatures(&commonFeatures, name); } - printf("uses-feature%s:'%s'\n", - req ? "" : "-not-required", - ResTable::normalizeForOutput(name.string()).string()); } else { int vers = getIntegerAttribute(tree, GL_ES_VERSION_ATTR, &error); @@ -1274,25 +1323,51 @@ int doDump(Bundle* bundle) String8 name = getAttribute(tree, NAME_ATTR, &error); if (name != "" && error == "") { if (name == "android.permission.CAMERA") { - hasCameraPermission = true; + addImpliedFeature(&impliedFeatures, "android.hardware.feature", + String8::format("requested %s permission", name.string()) + .string()); } else if (name == "android.permission.ACCESS_FINE_LOCATION") { - hasGpsPermission = true; + addImpliedFeature(&impliedFeatures, "android.hardware.location.gps", + String8::format("requested %s permission", name.string()) + .string()); + addImpliedFeature(&impliedFeatures, "android.hardware.location", + String8::format("requested %s permission", name.string()) + .string()); } else if (name == "android.permission.ACCESS_MOCK_LOCATION") { - hasMockLocPermission = true; + addImpliedFeature(&impliedFeatures, "android.hardware.location", + String8::format("requested %s permission", name.string()) + .string()); } else if (name == "android.permission.ACCESS_COARSE_LOCATION") { - hasCoarseLocPermission = true; + addImpliedFeature(&impliedFeatures, "android.hardware.location.network", + String8::format("requested %s permission", name.string()) + .string()); + addImpliedFeature(&impliedFeatures, "android.hardware.location", + String8::format("requested %s permission", name.string()) + .string()); } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" || name == "android.permission.INSTALL_LOCATION_PROVIDER") { - hasGeneralLocPermission = true; + addImpliedFeature(&impliedFeatures, "android.hardware.location", + String8::format("requested %s permission", name.string()) + .string()); } else if (name == "android.permission.BLUETOOTH" || name == "android.permission.BLUETOOTH_ADMIN") { - hasBluetoothPermission = true; + if (targetSdk > 4) { + addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth", + String8::format("requested %s permission", name.string()) + .string()); + addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth", + "targetSdkVersion > 4"); + } } else if (name == "android.permission.RECORD_AUDIO") { - hasRecordAudioPermission = true; + addImpliedFeature(&impliedFeatures, "android.hardware.microphone", + String8::format("requested %s permission", name.string()) + .string()); } else if (name == "android.permission.ACCESS_WIFI_STATE" || name == "android.permission.CHANGE_WIFI_STATE" || name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") { - hasWiFiPermission = true; + addImpliedFeature(&impliedFeatures, "android.hardware.wifi", + String8::format("requested %s permission", name.string()) + .string()); } else if (name == "android.permission.CALL_PHONE" || name == "android.permission.CALL_PRIVILEGED" || name == "android.permission.MODIFY_PHONE_STATE" || @@ -1304,7 +1379,8 @@ int doDump(Bundle* bundle) name == "android.permission.SEND_SMS" || name == "android.permission.WRITE_APN_SETTINGS" || name == "android.permission.WRITE_SMS") { - hasTelephonyPermission = true; + addImpliedFeature(&impliedFeatures, "android.hardware.telephony", + String8("requested a telephony permission").string()); } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") { hasWriteExternalStoragePermission = true; } else if (name == "android.permission.READ_EXTERNAL_STORAGE") { @@ -1430,10 +1506,12 @@ int doDump(Bundle* bundle) if (error == "") { if (orien == 0 || orien == 6 || orien == 8) { // Requests landscape, sensorLandscape, or reverseLandscape. - reqScreenLandscapeFeature = true; + addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape", + "one or more activities have specified a landscape orientation"); } else if (orien == 1 || orien == 7 || orien == 9) { // Requests portrait, sensorPortrait, or reversePortrait. - reqScreenPortraitFeature = true; + addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait", + "one or more activities have specified a portrait orientation"); } } } else if (tag == "uses-library") { @@ -1560,6 +1638,20 @@ int doDump(Bundle* bundle) goto bail; } } + } else if (withinFeatureGroup && tag == "uses-feature") { + String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error); + if (error != "") { + fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", + error.string()); + goto bail; + } + + int required = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1); + FeatureGroup& top = featureGroups.editTop(); + top.features.add(name, required); + if (required) { + addParentFeatures(&top, name); + } } } else if (depth == 4) { if (tag == "intent-filter") { @@ -1734,138 +1826,35 @@ int doDump(Bundle* bundle) } } - /* The following blocks handle printing "inferred" uses-features, based - * on whether related features or permissions are used by the app. - * Note that the various spec*Feature variables denote whether the - * relevant tag was *present* in the AndroidManfest, not that it was - * present and set to true. - */ - // Camera-related back-compatibility logic - if (!specCameraFeature) { - if (reqCameraFlashFeature) { - // if app requested a sub-feature (autofocus or flash) and didn't - // request the base camera feature, we infer that it meant to - printf("uses-feature:'android.hardware.camera'\n"); - printf("uses-implied-feature:'android.hardware.camera'," \ - "'requested android.hardware.camera.flash feature'\n"); - } else if (reqCameraAutofocusFeature) { - // if app requested a sub-feature (autofocus or flash) and didn't - // request the base camera feature, we infer that it meant to - printf("uses-feature:'android.hardware.camera'\n"); - printf("uses-implied-feature:'android.hardware.camera'," \ - "'requested android.hardware.camera.autofocus feature'\n"); - } else if (hasCameraPermission) { - // if app wants to use camera but didn't request the feature, we infer - // that it meant to, and further that it wants autofocus - // (which was the 1.0 - 1.5 behavior) - printf("uses-feature:'android.hardware.camera'\n"); - if (!specCameraAutofocusFeature) { - printf("uses-feature:'android.hardware.camera.autofocus'\n"); - printf("uses-implied-feature:'android.hardware.camera.autofocus'," \ - "'requested android.permission.CAMERA permission'\n"); + addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen", + "default feature for all apps"); + + const size_t numFeatureGroups = featureGroups.size(); + if (numFeatureGroups == 0) { + // If no <feature-group> tags were defined, apply auto-implied features. + printFeatureGroup(commonFeatures, &impliedFeatures); + + } else { + // <feature-group> tags are defined, so we ignore implied features and + for (size_t i = 0; i < numFeatureGroups; i++) { + FeatureGroup& grp = featureGroups.editItemAt(i); + + // Merge the features defined in the top level (not inside a <feature-group>) + // with this feature group. + const size_t numCommonFeatures = commonFeatures.features.size(); + for (size_t j = 0; j < numCommonFeatures; j++) { + if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) { + grp.features.add(commonFeatures.features.keyAt(j), commonFeatures.features[j]); + } } - } - } - // Location-related back-compatibility logic - if (!specLocationFeature && - (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission || - hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) { - // if app either takes a location-related permission or requests one of the - // sub-features, we infer that it also meant to request the base location feature - printf("uses-feature:'android.hardware.location'\n"); - printf("uses-implied-feature:'android.hardware.location'," \ - "'requested a location access permission'\n"); - } - if (!specGpsFeature && hasGpsPermission) { - // if app takes GPS (FINE location) perm but does not request the GPS - // feature, we infer that it meant to - printf("uses-feature:'android.hardware.location.gps'\n"); - printf("uses-implied-feature:'android.hardware.location.gps'," \ - "'requested android.permission.ACCESS_FINE_LOCATION permission'\n"); - } - if (!specNetworkLocFeature && hasCoarseLocPermission) { - // if app takes Network location (COARSE location) perm but does not request the - // network location feature, we infer that it meant to - printf("uses-feature:'android.hardware.location.network'\n"); - printf("uses-implied-feature:'android.hardware.location.network'," \ - "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n"); - } - - // Bluetooth-related compatibility logic - if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) { - // if app takes a Bluetooth permission but does not request the Bluetooth - // feature, we infer that it meant to - printf("uses-feature:'android.hardware.bluetooth'\n"); - printf("uses-implied-feature:'android.hardware.bluetooth'," \ - "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \ - "permission and targetSdkVersion > 4'\n"); - } - - // Microphone-related compatibility logic - if (!specMicrophoneFeature && hasRecordAudioPermission) { - // if app takes the record-audio permission but does not request the microphone - // feature, we infer that it meant to - printf("uses-feature:'android.hardware.microphone'\n"); - printf("uses-implied-feature:'android.hardware.microphone'," \ - "'requested android.permission.RECORD_AUDIO permission'\n"); - } - - // WiFi-related compatibility logic - if (!specWiFiFeature && hasWiFiPermission) { - // if app takes one of the WiFi permissions but does not request the WiFi - // feature, we infer that it meant to - printf("uses-feature:'android.hardware.wifi'\n"); - printf("uses-implied-feature:'android.hardware.wifi'," \ - "'requested android.permission.ACCESS_WIFI_STATE, " \ - "android.permission.CHANGE_WIFI_STATE, or " \ - "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n"); - } - - // Telephony-related compatibility logic - if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) { - // if app takes one of the telephony permissions or requests a sub-feature but - // does not request the base telephony feature, we infer that it meant to - printf("uses-feature:'android.hardware.telephony'\n"); - printf("uses-implied-feature:'android.hardware.telephony'," \ - "'requested a telephony-related permission or feature'\n"); - } - - // Touchscreen-related back-compatibility logic - if (!specTouchscreenFeature) { // not a typo! - // all apps are presumed to require a touchscreen, unless they explicitly say - // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> - // Note that specTouchscreenFeature is true if the tag is present, regardless - // of whether its value is true or false, so this is safe - printf("uses-feature:'android.hardware.touchscreen'\n"); - printf("uses-implied-feature:'android.hardware.touchscreen'," \ - "'assumed you require a touch screen unless explicitly made optional'\n"); - } - if (!specMultitouchFeature && reqDistinctMultitouchFeature) { - // if app takes one of the telephony permissions or requests a sub-feature but - // does not request the base telephony feature, we infer that it meant to - printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); - printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \ - "'requested android.hardware.touchscreen.multitouch.distinct feature'\n"); - } - - // Landscape/portrait-related compatibility logic - if (!specScreenLandscapeFeature && !specScreenPortraitFeature) { - // If the app has specified any activities in its manifest - // that request a specific orientation, then assume that - // orientation is required. - if (reqScreenLandscapeFeature) { - printf("uses-feature:'android.hardware.screen.landscape'\n"); - printf("uses-implied-feature:'android.hardware.screen.landscape'," \ - "'one or more activities have specified a landscape orientation'\n"); - } - if (reqScreenPortraitFeature) { - printf("uses-feature:'android.hardware.screen.portrait'\n"); - printf("uses-implied-feature:'android.hardware.screen.portrait'," \ - "'one or more activities have specified a portrait orientation'\n"); + if (!grp.features.isEmpty()) { + printFeatureGroup(grp); + } } } + if (hasWidgetReceivers) { printComponentPresence("app-widget"); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 70a7be8e1d18..03b5211b362f 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -619,39 +619,36 @@ public final class BridgeContext extends Context { } if (value != null) { - if ((value.getFirst() == ResourceType.STYLE) - || (value.getFirst() == ResourceType.ATTR)) { - // look for the style in the current theme, and its parent: - ResourceValue item = mRenderResources.findItemInTheme(value.getSecond(), + if ((value.getFirst() == ResourceType.STYLE)) { + // look for the style in all resources: + StyleResourceValue item = mRenderResources.getStyle(value.getSecond(), isFrameworkRes); if (item != null) { - if (item instanceof StyleResourceValue) { - if (defaultPropMap != null) { - defaultPropMap.put("style", item.getName()); - } - - defStyleValues = (StyleResourceValue)item; + if (defaultPropMap != null) { + defaultPropMap.put("style", item.getName()); } + + defStyleValues = item; } else { Bridge.getLog().error(null, String.format( "Style with id 0x%x (resolved to '%s') does not exist.", defStyleRes, value.getSecond()), - null /*data*/); + null); } } else { Bridge.getLog().error(null, String.format( - "Resouce id 0x%x is not of type STYLE (instead %s)", + "Resource id 0x%x is not of type STYLE (instead %s)", defStyleRes, value.getFirst().toString()), - null /*data*/); + null); } } else { Bridge.getLog().error(null, String.format( "Failed to find style with id 0x%x in current theme", defStyleRes), - null /*data*/); + null); } } diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk index 9ff56d634c21..99a56710371a 100644 --- a/tools/obbtool/Android.mk +++ b/tools/obbtool/Android.mk @@ -13,7 +13,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ Main.cpp -LOCAL_CFLAGS := -Wall -Werror +LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags #LOCAL_C_INCLUDES += @@ -36,7 +36,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := pbkdf2gen LOCAL_MODULE_TAGS := optional -LOCAL_CFLAGS := -Wall -Werror +LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags LOCAL_SRC_FILES := pbkdf2gen.cpp LOCAL_LDLIBS += -ldl LOCAL_C_INCLUDES := external/openssl/include $(LOCAL_C_INCLUDES) diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 292f1e87e4c4..71b6bee02134 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -24,6 +24,8 @@ import android.net.wifi.WifiInfo; import android.net.wifi.ScanSettings; import android.net.wifi.WifiChannel; import android.net.wifi.ScanResult; +import android.net.wifi.WifiConnectionStatistics; + import android.net.DhcpInfo; @@ -146,5 +148,7 @@ interface IWifiManager int getAllowScansWithTraffic(); void setAllowScansWithTraffic(int enabled); + + WifiConnectionStatistics getConnectionStatistics(); } diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index 50fd2609945a..57343c52262d 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -2,16 +2,20 @@ package android.net.wifi; import android.annotation.SystemApi; import android.content.Context; +import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.Messenger; +import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; import com.android.internal.util.AsyncChannel; +import com.android.internal.util.Protocol; import java.util.concurrent.CountDownLatch; @@ -51,12 +55,15 @@ public class RttManager { public static final int RTT_STATUS_ABORTED = 8; public static final int REASON_UNSPECIFIED = -1; - public static final int REASON_INVALID_LISTENER = -2; - public static final int REASON_INVALID_REQUEST = -3; + public static final int REASON_NOT_AVAILABLE = -2; + public static final int REASON_INVALID_LISTENER = -3; + public static final int REASON_INVALID_REQUEST = -4; + + public static final String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description"; public class Capabilities { - int supportedType; - int supportedPeerType; + public int supportedType; + public int supportedPeerType; } public Capabilities getCapabilities() { @@ -91,6 +98,73 @@ public class RttManager { public int num_retries; } + /** pseudo-private class used to parcel arguments */ + public static class ParcelableRttParams implements Parcelable { + + public RttParams mParams[]; + + ParcelableRttParams(RttParams[] params) { + mParams = params; + } + + /** Implement the Parcelable interface {@hide} */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + public void writeToParcel(Parcel dest, int flags) { + if (mParams != null) { + dest.writeInt(mParams.length); + + for (RttParams params : mParams) { + dest.writeInt(params.deviceType); + dest.writeInt(params.requestType); + dest.writeString(params.bssid); + dest.writeInt(params.frequency); + dest.writeInt(params.channelWidth); + dest.writeInt(params.num_samples); + dest.writeInt(params.num_retries); + } + } else { + dest.writeInt(0); + } + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<ParcelableRttParams> CREATOR = + new Creator<ParcelableRttParams>() { + public ParcelableRttParams createFromParcel(Parcel in) { + + int num = in.readInt(); + + if (num == 0) { + return new ParcelableRttParams(null); + } + + RttParams params[] = new RttParams[num]; + for (int i = 0; i < num; i++) { + params[i] = new RttParams(); + params[i].deviceType = in.readInt(); + params[i].requestType = in.readInt(); + params[i].bssid = in.readString(); + params[i].frequency = in.readInt(); + params[i].channelWidth = in.readInt(); + params[i].num_samples = in.readInt(); + params[i].num_retries = in.readInt(); + + } + + ParcelableRttParams parcelableParams = new ParcelableRttParams(params); + return parcelableParams; + } + + public ParcelableRttParams[] newArray(int size) { + return new ParcelableRttParams[size]; + } + }; + } + /** specifies RTT results */ public static class RttResult { /** mac address of the device being ranged */ @@ -99,6 +173,9 @@ public class RttManager { /** status of the request */ public int status; + /** type of the request used */ + public int requestType; + /** timestamp of completion, in microsecond since boot */ public long ts; @@ -121,24 +198,105 @@ public class RttManager { public long rtt_spread_ns; /** average distance in centimeter, computed based on rtt_ns */ - public long distance_cm; + public int distance_cm; /** standard deviation observed in distance */ - public long distance_sd_cm; + public int distance_sd_cm; /** spread (i.e. max - min) distance */ - public long distance_spread_cm; + public int distance_spread_cm; } + + /** pseudo-private class used to parcel results */ + public static class ParcelableRttResults implements Parcelable { + + public RttResult mResults[]; + + public ParcelableRttResults(RttResult[] results) { + mResults = results; + } + + /** Implement the Parcelable interface {@hide} */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + public void writeToParcel(Parcel dest, int flags) { + if (mResults != null) { + dest.writeInt(mResults.length); + for (RttResult result : mResults) { + dest.writeString(result.bssid); + dest.writeInt(result.status); + dest.writeInt(result.requestType); + dest.writeLong(result.ts); + dest.writeInt(result.rssi); + dest.writeInt(result.rssi_spread); + dest.writeInt(result.tx_rate); + dest.writeLong(result.rtt_ns); + dest.writeLong(result.rtt_sd_ns); + dest.writeLong(result.rtt_spread_ns); + dest.writeInt(result.distance_cm); + dest.writeInt(result.distance_sd_cm); + dest.writeInt(result.distance_spread_cm); + } + } else { + dest.writeInt(0); + } + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<ParcelableRttResults> CREATOR = + new Creator<ParcelableRttResults>() { + public ParcelableRttResults createFromParcel(Parcel in) { + + int num = in.readInt(); + + if (num == 0) { + return new ParcelableRttResults(null); + } + + RttResult results[] = new RttResult[num]; + for (int i = 0; i < num; i++) { + results[i] = new RttResult(); + results[i].bssid = in.readString(); + results[i].status = in.readInt(); + results[i].requestType = in.readInt(); + results[i].ts = in.readLong(); + results[i].rssi = in.readInt(); + results[i].rssi_spread = in.readInt(); + results[i].tx_rate = in.readInt(); + results[i].rtt_ns = in.readLong(); + results[i].rtt_sd_ns = in.readLong(); + results[i].rtt_spread_ns = in.readLong(); + results[i].distance_cm = in.readInt(); + results[i].distance_sd_cm = in.readInt(); + results[i].distance_spread_cm = in.readInt(); + } + + ParcelableRttResults parcelableResults = new ParcelableRttResults(results); + return parcelableResults; + } + + public ParcelableRttResults[] newArray(int size) { + return new ParcelableRttResults[size]; + } + }; + } + + public static interface RttListener { - public void onSuccess(RttResult results[]); + public void onSuccess(RttResult[] results); public void onFailure(int reason, String description); public void onAborted(); } - public void startRanging(RttParams params[], RttListener listener) { + public void startRanging(RttParams[] params, RttListener listener) { validateChannel(); - sAsyncChannel.sendMessage(CMD_OP_START_RANGING, 0, removeListener(listener), params); + ParcelableRttParams parcelableParams = new ParcelableRttParams(params); + sAsyncChannel.sendMessage(CMD_OP_START_RANGING, + 0, putListener(listener), parcelableParams); } public void stopRanging(RttListener listener) { @@ -147,11 +305,13 @@ public class RttManager { } /* private methods */ - public static final int CMD_OP_START_RANGING = 0; - public static final int CMD_OP_STOP_RANGING = 1; - public static final int CMD_OP_FAILED = 2; - public static final int CMD_OP_SUCCEEDED = 3; - public static final int CMD_OP_ABORTED = 4; + public static final int BASE = Protocol.BASE_WIFI_RTT_MANAGER; + + public static final int CMD_OP_START_RANGING = BASE + 0; + public static final int CMD_OP_STOP_RANGING = BASE + 1; + public static final int CMD_OP_FAILED = BASE + 2; + public static final int CMD_OP_SUCCEEDED = BASE + 3; + public static final int CMD_OP_ABORTED = BASE + 4; private Context mContext; private IRttManager mService; @@ -173,7 +333,7 @@ public class RttManager { * Create a new WifiScanner instance. * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve - * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. + * the standard {@link android.content.Context#WIFI_RTT_SERVICE Context.WIFI_RTT_SERVICE}. * @param context the application context * @param service the Binder interface * @hide @@ -190,6 +350,7 @@ public class RttManager { if (++sThreadRefCount == 1) { Messenger messenger = null; try { + Log.d(TAG, "Get the messenger from " + mService); messenger = mService.getMessenger(); } catch (RemoteException e) { /* do nothing */ @@ -313,10 +474,11 @@ public class RttManager { switch (msg.what) { /* ActionListeners grouped together */ case CMD_OP_SUCCEEDED : - ((RttListener) listener).onSuccess((RttResult[])msg.obj); + reportSuccess(listener, msg); + removeListener(msg.arg2); break; case CMD_OP_FAILED : - ((RttListener) listener).onFailure(msg.arg1, (String)msg.obj); + reportFailure(listener, msg); removeListener(msg.arg2); break; case CMD_OP_ABORTED : @@ -328,6 +490,18 @@ public class RttManager { return; } } + + void reportSuccess(Object listener, Message msg) { + RttListener rttListener = (RttListener) listener; + ParcelableRttResults parcelableResults = (ParcelableRttResults) msg.obj; + ((RttListener) listener).onSuccess(parcelableResults.mResults); + } + + void reportFailure(Object listener, Message msg) { + RttListener rttListener = (RttListener) listener; + Bundle bundle = (Bundle) msg.obj; + ((RttListener) listener).onFailure(msg.arg1, bundle.getString(DESCRIPTION_KEY)); + } } } diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index 4a4b9ff0a779..73de099eb041 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -28,13 +28,19 @@ import android.os.Parcel; * but does not currently report them to external clients. */ public class ScanResult implements Parcelable { - /** The network name. */ + /** + * The network name. + */ public String SSID; - /** Ascii encoded SSID. This will replace SSID when we deprecate it. @hide */ + /** + * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide + */ public WifiSsid wifiSsid; - /** The address of the access point. */ + /** + * The address of the access point. + */ public String BSSID; /** * Describes the authentication, key management, and encryption schemes @@ -63,6 +69,27 @@ public class ScanResult implements Parcelable { */ public long seen; + /** + * @hide + * Update RSSI of the scan result + * @param previousRSSI + * @param previousSeen + * @param maxAge + */ + public void averageRssi(int previousRssi, long previousSeen, int maxAge) { + + if (seen == 0) { + seen = System.currentTimeMillis(); + } + long age = seen - previousSeen; + + if (previousSeen > 0 && age > 0 && age < maxAge/2) { + // Average the RSSI with previously seen instances of this scan result + double alpha = 0.5 - (double) age / (double) maxAge; + level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha); + } + } + /** @hide */ public static final int ENABLED = 0; /** @hide */ @@ -79,6 +106,25 @@ public class ScanResult implements Parcelable { public int status; /** + * Status: indicating the scan result is not a result + * that is part of user's saved configurations + * @hide + */ + public boolean untrusted; + + /** + * Number of time we connected to it + * @hide + */ + public int numConnection; + + /** + * Number of time autojoin used it + * @hide + */ + public int numUsage; + + /** * The approximate distance to the AP in centimeter, if available. Else * {@link UNSPECIFIED}. * {@hide} @@ -105,18 +151,32 @@ public class ScanResult implements Parcelable { public final static int UNSPECIFIED = -1; /** * @hide - * TODO: makes real freq boundaries */ public boolean is24GHz() { - return frequency > 2400 && frequency < 2500; + return ScanResult.is24GHz(frequency); } /** * @hide * TODO: makes real freq boundaries */ + public static boolean is24GHz(int freq) { + return freq > 2400 && freq < 2500; + } + + /** + * @hide + */ public boolean is5GHz() { - return frequency > 4900 && frequency < 5900; + return ScanResult.is24GHz(frequency); + } + + /** + * @hide + * TODO: makes real freq boundaries + */ + public static boolean is5GHz(int freq) { + return freq > 4900 && freq < 5900; } /** information element from beacon @@ -175,6 +235,9 @@ public class ScanResult implements Parcelable { seen = source.seen; passpoint = source.passpoint; status = source.status; + untrusted = source.untrusted; + numConnection = source.numConnection; + numUsage = source.numUsage; } } @@ -237,6 +300,9 @@ public class ScanResult implements Parcelable { dest.writeInt(distanceSdCm); dest.writeLong(seen); dest.writeInt(status); + dest.writeInt(untrusted ? 1 : 0); + dest.writeInt(numConnection); + dest.writeInt(numUsage); if (passpoint != null) { dest.writeInt(1); passpoint.writeToParcel(dest, flags); @@ -275,6 +341,9 @@ public class ScanResult implements Parcelable { ); sr.seen = in.readLong(); sr.status = in.readInt(); + sr.untrusted = in.readInt() != 0; + sr.numConnection = in.readInt(); + sr.numUsage = in.readInt(); if (in.readInt() == 1) { sr.passpoint = WifiPasspointInfo.CREATOR.createFromParcel(in); } diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index b48269762c8b..dd30ac7bfdb7 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -357,6 +357,7 @@ public class WifiConfiguration implements Parcelable { * @hide * Uid of last app modifying the configuration */ + @SystemApi public int lastUpdateUid; /** @@ -668,6 +669,14 @@ public class WifiConfiguration implements Parcelable { /** * @hide + * Number of time we associated to this configuration. + */ + @SystemApi + public int numAssociation; + + + /** + * @hide * Connect choices * * remember the keys identifying the known WifiConfiguration over which this configuration @@ -1187,6 +1196,7 @@ public class WifiConfiguration implements Parcelable { numConnectionFailures = source.numConnectionFailures; numScorerOverride = source.numScorerOverride; numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork; + numAssociation = source.numAssociation; } } @@ -1238,6 +1248,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(numConnectionFailures); dest.writeInt(numScorerOverride); dest.writeInt(numScorerOverrideAndSwitchedNetwork); + dest.writeInt(numAssociation); } /** Implement the Parcelable interface {@hide} */ @@ -1285,6 +1296,7 @@ public class WifiConfiguration implements Parcelable { config.numConnectionFailures = in.readInt(); config.numScorerOverride = in.readInt(); config.numScorerOverrideAndSwitchedNetwork = in.readInt(); + config.numAssociation = in.readInt(); return config; } diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl b/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl new file mode 100644 index 000000000000..601facea37ba --- /dev/null +++ b/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl @@ -0,0 +1,19 @@ +/** + * 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 android.net.wifi; + +parcelable WifiConnectionStatistics; diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.java b/wifi/java/android/net/wifi/WifiConnectionStatistics.java new file mode 100644 index 000000000000..8e79a17e348e --- /dev/null +++ b/wifi/java/android/net/wifi/WifiConnectionStatistics.java @@ -0,0 +1,138 @@ +/* + * 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 android.net.wifi; + +import android.annotation.SystemApi; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.util.HashMap; + +/** + * Wifi Connection Statistics: gather various stats regarding WiFi connections, + * connection requests, auto-join + * and WiFi usage. + * @hide + */ +@SystemApi +public class WifiConnectionStatistics implements Parcelable { + private static final String TAG = "WifiConnnectionStatistics"; + + /** + * history of past connection to untrusted SSID + * Key = SSID + * Value = num connection + */ + public HashMap<String, WifiNetworkConnectionStatistics> untrustedNetworkHistory; + + // Number of time we polled the chip and were on 5GHz + public int num5GhzConnected; + + // Number of time we polled the chip and were on 2.4GHz + public int num24GhzConnected; + + public WifiConnectionStatistics() { + untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>(); + } + + public void incrementOrAddUntrusted(String SSID, int connection, int usage) { + WifiNetworkConnectionStatistics stats; + if (TextUtils.isEmpty(SSID)) + return; + if (untrustedNetworkHistory.containsKey(SSID)) { + stats = untrustedNetworkHistory.get(SSID); + if (stats != null){ + stats.numConnection = connection + stats.numConnection; + stats.numUsage = usage + stats.numUsage; + } + } else { + stats = new WifiNetworkConnectionStatistics(connection, usage); + } + if (stats != null) { + untrustedNetworkHistory.put(SSID, stats); + } + } + + @Override + public String toString() { + StringBuilder sbuf = new StringBuilder(); + sbuf.append("Connected on: 2.4Ghz=").append(num24GhzConnected); + sbuf.append(" 5Ghz=").append(num5GhzConnected).append("\n"); + + for (String Key : untrustedNetworkHistory.keySet()) { + WifiNetworkConnectionStatistics stats = untrustedNetworkHistory.get(Key); + if (stats != null) { + sbuf.append(Key).append(" ").append(stats.toString()).append("\n"); + } + } + return sbuf.toString(); + } + + /** copy constructor*/ + public WifiConnectionStatistics(WifiConnectionStatistics source) { + untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>(); + if (source != null) { + untrustedNetworkHistory.putAll(source.untrustedNetworkHistory); + } + } + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(num24GhzConnected); + dest.writeInt(num5GhzConnected); + dest.writeInt(untrustedNetworkHistory.size()); + for (String Key : untrustedNetworkHistory.keySet()) { + WifiNetworkConnectionStatistics num = untrustedNetworkHistory.get(Key); + dest.writeString(Key); + dest.writeInt(num.numConnection); + dest.writeInt(num.numUsage); + + } + } + + /** Implement the Parcelable interface */ + public static final Creator<WifiConnectionStatistics> CREATOR = + new Creator<WifiConnectionStatistics>() { + public WifiConnectionStatistics createFromParcel(Parcel in) { + WifiConnectionStatistics stats = new WifiConnectionStatistics(); + stats.num24GhzConnected = in.readInt(); + stats.num5GhzConnected = in.readInt(); + int n = in.readInt(); + while (n-- > 0) { + String Key = in.readString(); + int numConnection = in.readInt(); + int numUsage = in.readInt(); + WifiNetworkConnectionStatistics st = + new WifiNetworkConnectionStatistics(numConnection, numUsage); + stats.untrustedNetworkHistory.put(Key, st); + } + return stats; + } + + public WifiConnectionStatistics[] newArray(int size) { + return new WifiConnectionStatistics[size]; + } + }; +} diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index e46f9169f886..e8081368dc70 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -371,7 +371,7 @@ public class WifiInfo implements Parcelable { * TODO: makes real freq boundaries */ public boolean is24GHz() { - return mFrequency < 4000; + return ScanResult.is24GHz(mFrequency); } /** @@ -379,7 +379,7 @@ public class WifiInfo implements Parcelable { * TODO: makes real freq boundaries */ public boolean is5GHz() { - return mFrequency > 4000; + return ScanResult.is5GHz(mFrequency); } /** diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 8945e52e4db7..dfed174821f2 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -639,6 +639,16 @@ public class WifiManager { } } + /** @hide */ + @SystemApi + public WifiConnectionStatistics getConnectionStatistics() { + try { + return mService.getConnectionStatistics(); + } catch (RemoteException e) { + return null; + } + } + /** * Add a new network description to the set of configured networks. * The {@code networkId} field of the supplied configuration object diff --git a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.aidl b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.aidl new file mode 100644 index 000000000000..5f497e2796d8 --- /dev/null +++ b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.aidl @@ -0,0 +1,19 @@ +/** + * 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 android.net.wifi; + +parcelable WifiNetworkConnectionStatistics; diff --git a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java new file mode 100644 index 000000000000..c7d62e5312af --- /dev/null +++ b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java @@ -0,0 +1,87 @@ +/* + * 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 android.net.wifi; + +import android.annotation.SystemApi; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.HashMap; + +/** + * Connection Statistics For a WiFi Network. + * @hide + */ +@SystemApi +public class WifiNetworkConnectionStatistics implements Parcelable { + private static final String TAG = "WifiNetworkConnnectionStatistics"; + + public int numConnection; + public int numUsage; + + public WifiNetworkConnectionStatistics(int connection, int usage) { + numConnection = connection; + numUsage = usage; + } + + public WifiNetworkConnectionStatistics() { } + + + @Override + public String toString() { + StringBuilder sbuf = new StringBuilder(); + sbuf.append("c=").append(numConnection); + sbuf.append(" u=").append(numUsage); + return sbuf.toString(); + } + + + /** copy constructor*/ + public WifiNetworkConnectionStatistics(WifiNetworkConnectionStatistics source) { + numConnection = source.numConnection; + numUsage = source.numUsage; + } + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(numConnection); + dest.writeInt(numUsage); + } + + /** Implement the Parcelable interface */ + public static final Creator<WifiNetworkConnectionStatistics> CREATOR = + new Creator<WifiNetworkConnectionStatistics>() { + public WifiNetworkConnectionStatistics createFromParcel(Parcel in) { + int numConnection = in.readInt(); + int numUsage = in.readInt(); + WifiNetworkConnectionStatistics stats = + new WifiNetworkConnectionStatistics(numConnection, numUsage); + return stats; + } + + public WifiNetworkConnectionStatistics[] newArray(int size) { + return new WifiNetworkConnectionStatistics[size]; + } + }; +} |