Merge "Make sure the theta is correctly represented and incoming polygon is CW for shadow."
diff --git a/Android.mk b/Android.mk
index be7e055..232f5bf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -180,6 +180,8 @@
core/java/android/os/IUserManager.aidl \
core/java/android/os/IVibratorService.aidl \
core/java/android/service/notification/INotificationListener.aidl \
+ core/java/android/service/notification/IConditionListener.aidl \
+ core/java/android/service/notification/IConditionProvider.aidl \
core/java/android/print/ILayoutResultCallback.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
core/java/android/print/IPrintDocumentAdapter.aidl \
@@ -197,6 +199,9 @@
core/java/android/service/dreams/IDreamService.aidl \
core/java/android/service/trust/ITrustAgentService.aidl \
core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
+ core/java/android/service/voice/IVoiceInteractionService.aidl \
+ core/java/android/service/voice/IVoiceInteractionSession.aidl \
+ core/java/android/service/voice/IVoiceInteractionSessionService.aidl \
core/java/android/service/wallpaper/IWallpaperConnection.aidl \
core/java/android/service/wallpaper/IWallpaperEngine.aidl \
core/java/android/service/wallpaper/IWallpaperService.aidl \
@@ -230,6 +235,10 @@
core/java/com/android/internal/app/IBatteryStats.aidl \
core/java/com/android/internal/app/IProcessStats.aidl \
core/java/com/android/internal/app/IUsageStats.aidl \
+ core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
+ core/java/com/android/internal/app/IVoiceInteractor.aidl \
+ core/java/com/android/internal/app/IVoiceInteractorCallback.aidl \
+ core/java/com/android/internal/app/IVoiceInteractorRequest.aidl \
core/java/com/android/internal/app/IMediaContainerService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
diff --git a/api/current.txt b/api/current.txt
index ef6aed7..1c8698a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31,6 +31,7 @@
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TRUST_AGENT_SERVICE = "android.permission.BIND_TRUST_AGENT_SERVICE";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+ field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
@@ -284,6 +285,7 @@
field public static final int allContactsName = 16843468; // 0x10102cc
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
+ field public static final int allowEmbedded = 16843765; // 0x10103f5
field public static final int allowParallelSyncs = 16843570; // 0x1010332
field public static final int allowSingleTap = 16843353; // 0x1010259
field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -489,6 +491,7 @@
field public static final int editTextStyle = 16842862; // 0x101006e
field public static final deprecated int editable = 16843115; // 0x101016b
field public static final int editorExtras = 16843300; // 0x1010224
+ field public static final int elevation = 16843852; // 0x101044c
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
@@ -700,7 +703,6 @@
field public static final int l_resource_pad25 = 16843768; // 0x10103f8
field public static final int l_resource_pad26 = 16843767; // 0x10103f7
field public static final int l_resource_pad27 = 16843766; // 0x10103f6
- field public static final int l_resource_pad28 = 16843765; // 0x10103f5
field public static final int l_resource_pad3 = 16843790; // 0x101040e
field public static final int l_resource_pad4 = 16843789; // 0x101040d
field public static final int l_resource_pad5 = 16843788; // 0x101040c
@@ -825,6 +827,7 @@
field public static final int name = 16842755; // 0x1010003
field public static final int navigationMode = 16843471; // 0x10102cf
field public static final int negativeButtonText = 16843254; // 0x10101f6
+ field public static final int nestedScrollingEnabled = 16843843; // 0x1010443
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -1007,6 +1010,7 @@
field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
field public static final int sequence = 16843815; // 0x1010427
+ field public static final int sessionService = 16843850; // 0x101044a
field public static final int settingsActivity = 16843301; // 0x1010225
field public static final int shadowColor = 16843105; // 0x1010161
field public static final int shadowDx = 16843106; // 0x1010162
@@ -1102,6 +1106,7 @@
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
field public static final int switchPreferenceStyle = 16843629; // 0x101036d
+ field public static final int switchStyle = 16843851; // 0x101044b
field public static final int switchTextAppearance = 16843630; // 0x101036e
field public static final int switchTextOff = 16843628; // 0x101036c
field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1285,8 +1290,8 @@
field public static final int windowActionBar = 16843469; // 0x10102cd
field public static final int windowActionBarOverlay = 16843492; // 0x10102e4
field public static final int windowActionModeOverlay = 16843485; // 0x10102dd
- field public static final int windowAllowEnterTransitionOverlap = 16843848; // 0x1010448
- field public static final int windowAllowExitTransitionOverlap = 16843847; // 0x1010447
+ field public static final int windowAllowEnterTransitionOverlap = 16843849; // 0x1010449
+ field public static final int windowAllowExitTransitionOverlap = 16843848; // 0x1010448
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
@@ -1296,9 +1301,9 @@
field public static final int windowDisablePreview = 16843298; // 0x1010222
field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
field public static final int windowEnterAnimation = 16842932; // 0x10100b4
- field public static final int windowEnterTransition = 16843843; // 0x1010443
+ field public static final int windowEnterTransition = 16843844; // 0x1010444
field public static final int windowExitAnimation = 16842933; // 0x10100b5
- field public static final int windowExitTransition = 16843844; // 0x1010444
+ field public static final int windowExitTransition = 16843845; // 0x1010445
field public static final int windowFrame = 16842837; // 0x1010055
field public static final int windowFullscreen = 16843277; // 0x101020d
field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1309,8 +1314,8 @@
field public static final int windowNoDisplay = 16843294; // 0x101021e
field public static final int windowNoTitle = 16842838; // 0x1010056
field public static final int windowOverscan = 16843727; // 0x10103cf
- field public static final int windowSharedElementEnterTransition = 16843845; // 0x1010445
- field public static final int windowSharedElementExitTransition = 16843846; // 0x1010446
+ field public static final int windowSharedElementEnterTransition = 16843846; // 0x1010446
+ field public static final int windowSharedElementExitTransition = 16843847; // 0x1010447
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1661,10 +1666,14 @@
field public static final int decelerate_cubic = 17563651; // 0x10c0003
field public static final int decelerate_quad = 17563649; // 0x10c0001
field public static final int decelerate_quint = 17563653; // 0x10c0005
- field public static final int fast_out_linear_in = 17563663; // 0x10c000f
- field public static final int fast_out_slow_in = 17563661; // 0x10c000d
+ field public static final int fast_out_linear_in = 17563667; // 0x10c0013
+ field public static final int fast_out_slow_in = 17563665; // 0x10c0011
+ field public static final int l_resource_pad1 = 17563664; // 0x10c0010
+ field public static final int l_resource_pad2 = 17563663; // 0x10c000f
+ field public static final int l_resource_pad3 = 17563662; // 0x10c000e
+ field public static final int l_resource_pad4 = 17563661; // 0x10c000d
field public static final int linear = 17563659; // 0x10c000b
- field public static final int linear_out_slow_in = 17563662; // 0x10c000e
+ field public static final int linear_out_slow_in = 17563666; // 0x10c0012
field public static final int overshoot = 17563656; // 0x10c0008
}
@@ -3201,6 +3210,7 @@
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
+ method public android.app.VoiceInteractor getVoiceInteractor();
method public final int getVolumeControlStream();
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
@@ -3212,6 +3222,7 @@
method public boolean isFinishing();
method public boolean isImmersive();
method public boolean isTaskRoot();
+ method public boolean isVoiceInteraction();
method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public boolean moveTaskToBack(boolean);
method public boolean navigateUpTo(android.content.Intent);
@@ -4837,6 +4848,29 @@
field public static final int MODE_NIGHT_YES = 2; // 0x2
}
+ public class VoiceInteractor {
+ method public boolean submitRequest(android.app.VoiceInteractor.Request);
+ method public boolean[] supportsCommands(java.lang.String[]);
+ }
+
+ public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request {
+ ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle);
+ method public void onCommandResult(android.os.Bundle);
+ }
+
+ public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request {
+ ctor public VoiceInteractor.ConfirmationRequest(java.lang.CharSequence, android.os.Bundle);
+ method public void onConfirmationResult(boolean, android.os.Bundle);
+ }
+
+ public static abstract class VoiceInteractor.Request {
+ ctor public VoiceInteractor.Request();
+ method public void cancel();
+ method public android.app.Activity getActivity();
+ method public android.content.Context getContext();
+ method public void onCancel();
+ }
+
public final class WallpaperInfo implements android.os.Parcelable {
ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
@@ -4946,7 +4980,9 @@
public class DevicePolicyManager {
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
+ method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
+ method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5009,6 +5045,9 @@
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
+ field public static final int KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 4; // 0x4
+ field public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 16; // 0x10
+ field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -6996,6 +7035,7 @@
field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
+ field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
field public static final android.os.Parcelable.Creator CREATOR;
field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -7711,6 +7751,7 @@
method public long getFirstInstallTime();
method public android.graphics.drawable.Drawable getIcon(int);
method public java.lang.CharSequence getLabel();
+ method public java.lang.String getName();
method public android.os.UserHandle getUser();
}
@@ -9709,6 +9750,7 @@
method public void drawRect(android.graphics.Rect, android.graphics.Paint);
method public void drawRect(float, float, float, float, android.graphics.Paint);
method public void drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint);
+ method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
method public void drawText(char[], int, int, float, float, android.graphics.Paint);
method public void drawText(java.lang.String, float, float, android.graphics.Paint);
method public void drawText(java.lang.String, int, int, float, float, android.graphics.Paint);
@@ -10021,11 +10063,18 @@
method public void setPaint(android.graphics.Paint);
}
- public class Outline {
+ public final class Outline {
ctor public Outline();
- method public final boolean isValid();
+ ctor public Outline(android.graphics.Outline);
+ method public boolean isValid();
method public void set(android.graphics.Outline);
+ method public void setConvexPath(android.graphics.Path);
+ method public void setOval(int, int, int, int);
+ method public void setOval(android.graphics.Rect);
+ method public void setRect(int, int, int, int);
+ method public void setRect(android.graphics.Rect);
method public void setRoundRect(int, int, int, int, float);
+ method public void setRoundRect(android.graphics.Rect, float);
}
public class Paint {
@@ -10194,6 +10243,7 @@
method public void addArc(android.graphics.RectF, float, float);
method public void addCircle(float, float, float, android.graphics.Path.Direction);
method public void addOval(android.graphics.RectF, android.graphics.Path.Direction);
+ method public void addOval(float, float, float, float, android.graphics.Path.Direction);
method public void addPath(android.graphics.Path, float, float);
method public void addPath(android.graphics.Path);
method public void addPath(android.graphics.Path, android.graphics.Matrix);
@@ -10748,7 +10798,7 @@
method public int getMinimumHeight();
method public int getMinimumWidth();
method public abstract int getOpacity();
- method public android.graphics.Outline getOutline();
+ method public boolean getOutline(android.graphics.Outline);
method public boolean getPadding(android.graphics.Rect);
method public int[] getState();
method public android.graphics.Region getTransparentRegion();
@@ -11121,6 +11171,7 @@
method public android.graphics.drawable.shapes.Shape clone() throws java.lang.CloneNotSupportedException;
method public abstract void draw(android.graphics.Canvas, android.graphics.Paint);
method public final float getHeight();
+ method public boolean getOutline(android.graphics.Outline);
method public final float getWidth();
method public boolean hasAlpha();
method protected void onResize(float, float);
@@ -13375,6 +13426,18 @@
ctor public DeniedByServerException(java.lang.String);
}
+ public final class DngCreator {
+ ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult);
+ method public android.media.DngCreator setDescription(java.lang.String);
+ method public android.media.DngCreator setLocation(android.location.Location);
+ method public android.media.DngCreator setOrientation(int);
+ method public android.media.DngCreator setThumbnail(android.graphics.Bitmap);
+ method public android.media.DngCreator setThumbnail(android.media.Image);
+ method public void writeByteBuffer(java.io.OutputStream, java.nio.ByteBuffer, int, long) throws java.io.IOException;
+ method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException;
+ method public void writeInputStream(java.io.OutputStream, java.io.InputStream, int, long) throws java.io.IOException;
+ }
+
public class ExifInterface {
ctor public ExifInterface(java.lang.String) throws java.io.IOException;
method public double getAltitude(double);
@@ -24864,6 +24927,42 @@
}
+package android.service.voice {
+
+ public class VoiceInteractionService extends android.app.Service {
+ ctor public VoiceInteractionService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public void startVoiceActivity(android.content.Intent, android.os.Bundle);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
+ field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
+ }
+
+ public abstract class VoiceInteractionSession {
+ ctor public VoiceInteractionSession(android.content.Context);
+ ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
+ method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
+ method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+ method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+ method public abstract boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
+ }
+
+ public static class VoiceInteractionSession.Caller {
+ }
+
+ public static class VoiceInteractionSession.Request {
+ method public void sendCancelResult();
+ method public void sendCommandResult(boolean, android.os.Bundle);
+ method public void sendConfirmResult(boolean, android.os.Bundle);
+ }
+
+ public abstract class VoiceInteractionSessionService extends android.app.Service {
+ ctor public VoiceInteractionSessionService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract android.service.voice.VoiceInteractionSession onNewSession(android.os.Bundle);
+ }
+
+}
+
package android.service.wallpaper {
public abstract class WallpaperService extends android.app.Service {
@@ -25441,18 +25540,6 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
- public class DataConnectionRealTimeInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getDcPowerState();
- method public long getTime();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static int DC_POWER_STATE_HIGH;
- field public static int DC_POWER_STATE_LOW;
- field public static int DC_POWER_STATE_MEDIUM;
- field public static int DC_POWER_STATE_UNKNOWN;
- }
-
public class NeighboringCellInfo implements android.os.Parcelable {
ctor public deprecated NeighboringCellInfo();
ctor public deprecated NeighboringCellInfo(int, int);
@@ -28076,12 +28163,19 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.tv.TvInputService";
}
- public abstract class TvInputService.TvInputSessionImpl {
+ public abstract class TvInputService.TvInputSessionImpl implements android.view.KeyEvent.Callback {
ctor public TvInputService.TvInputSessionImpl();
method public android.view.View onCreateOverlayView();
+ method public boolean onGenericMotionEvent(android.view.MotionEvent);
+ method public boolean onKeyDown(int, android.view.KeyEvent);
+ method public boolean onKeyLongPress(int, android.view.KeyEvent);
+ method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
+ method public boolean onKeyUp(int, android.view.KeyEvent);
method public abstract void onRelease();
method public abstract boolean onSetSurface(android.view.Surface);
method public abstract void onSetVolume(float);
+ 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 setOverlayViewEnabled(boolean);
}
@@ -28091,9 +28185,16 @@
ctor public TvView(android.content.Context, android.util.AttributeSet);
ctor public TvView(android.content.Context, android.util.AttributeSet, int);
method public void bindTvInput(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback);
+ method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
+ method public boolean onUnhandledInputEvent(android.view.InputEvent);
+ method public void setOnUnhandledInputEventListener(android.tv.TvView.OnUnhandledInputEventListener);
method public void unbindTvInput();
}
+ public static abstract interface TvView.OnUnhandledInputEventListener {
+ method public abstract boolean onUnhandledInputEvent(android.view.InputEvent);
+ }
+
}
package android.util {
@@ -29983,6 +30084,9 @@
method public boolean dispatchKeyEvent(android.view.KeyEvent);
method public boolean dispatchKeyEventPreIme(android.view.KeyEvent);
method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
+ method public boolean dispatchNestedFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]);
method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
@@ -30032,6 +30136,7 @@
method public int getDrawingCacheQuality();
method public void getDrawingRect(android.graphics.Rect);
method public long getDrawingTime();
+ method public float getElevation();
method public boolean getFilterTouchesWhenObscured();
method public boolean getFitsSystemWindows();
method public java.util.ArrayList<android.view.View> getFocusables(int);
@@ -30130,8 +30235,10 @@
method public void getWindowVisibleDisplayFrame(android.graphics.Rect);
method public float getX();
method public float getY();
+ method public float getZ();
method public boolean hasFocus();
method public boolean hasFocusable();
+ method public boolean hasNestedScrollingParent();
method public boolean hasOnClickListeners();
method public boolean hasOverlappingRendering();
method public boolean hasTransientState();
@@ -30167,6 +30274,7 @@
method public boolean isLayoutDirectionResolved();
method public boolean isLayoutRequested();
method public boolean isLongClickable();
+ method public boolean isNestedScrollingEnabled();
method public boolean isOpaque();
method protected boolean isPaddingOffsetRequired();
method public boolean isPaddingRelative();
@@ -30294,6 +30402,7 @@
method public void setDrawingCacheEnabled(boolean);
method public void setDrawingCacheQuality(int);
method public void setDuplicateParentStateEnabled(boolean);
+ method public void setElevation(float);
method public void setEnabled(boolean);
method public void setFadingEdgeLength(int);
method public void setFilterTouchesWhenObscured(boolean);
@@ -30318,6 +30427,7 @@
method protected final void setMeasuredDimension(int, int);
method public void setMinimumHeight(int);
method public void setMinimumWidth(int);
+ method public void setNestedScrollingEnabled(boolean);
method public void setNextFocusDownId(int);
method public void setNextFocusForwardId(int);
method public void setNextFocusLeftId(int);
@@ -30378,10 +30488,13 @@
method public void setWillNotDraw(boolean);
method public void setX(float);
method public void setY(float);
+ method public void setZ(float);
method public boolean showContextMenu();
method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
method public void startAnimation(android.view.animation.Animation);
method public final boolean startDrag(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
+ method public boolean startNestedScroll(int);
+ method public void stopNestedScroll();
method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
method public void unscheduleDrawable(android.graphics.drawable.Drawable);
method protected boolean verifyDrawable(android.graphics.drawable.Drawable);
@@ -30470,6 +30583,9 @@
field public static final int SCROLLBAR_POSITION_DEFAULT = 0; // 0x0
field public static final int SCROLLBAR_POSITION_LEFT = 1; // 0x1
field public static final int SCROLLBAR_POSITION_RIGHT = 2; // 0x2
+ field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+ field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+ field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
field protected static final int[] SELECTED_STATE_SET;
field protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET;
field public static final int SOUND_EFFECTS_ENABLED = 134217728; // 0x8000000
@@ -30739,6 +30855,7 @@
method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener();
method public int getLayoutMode();
method public android.animation.LayoutTransition getLayoutTransition();
+ method public int getNestedScrollAxes();
method public int getPersistentDrawingCache();
method public int indexOfChild(android.view.View);
method public final void invalidateChild(android.view.View, android.graphics.Rect);
@@ -30759,8 +30876,14 @@
method public boolean onInterceptHoverEvent(android.view.MotionEvent);
method public boolean onInterceptTouchEvent(android.view.MotionEvent);
method protected abstract void onLayout(boolean, int, int, int, int);
+ method public boolean onNestedFling(android.view.View, float, float);
+ method public void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
method protected boolean onRequestFocusInDescendants(int, android.graphics.Rect);
method public boolean onRequestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
+ method public void onStopNestedScroll(android.view.View);
method public void recomputeViewAttributes(android.view.View);
method public void removeAllViews();
method public void removeAllViewsInLayout();
@@ -30891,6 +31014,12 @@
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
+ method public abstract boolean onNestedFling(android.view.View, float, float);
+ method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public abstract void onNestedScroll(android.view.View, int, int, int, int);
+ method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public abstract boolean onStartNestedScroll(android.view.View, android.view.View, int);
+ method public abstract void onStopNestedScroll(android.view.View);
method public abstract void recomputeViewAttributes(android.view.View);
method public abstract void requestChildFocus(android.view.View, android.view.View);
method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
@@ -30939,6 +31068,8 @@
method public android.view.ViewPropertyAnimator xBy(float);
method public android.view.ViewPropertyAnimator y(float);
method public android.view.ViewPropertyAnimator yBy(float);
+ method public android.view.ViewPropertyAnimator z(float);
+ method public android.view.ViewPropertyAnimator zBy(float);
}
public final class ViewStub extends android.view.View {
@@ -34420,6 +34551,7 @@
method public void setExcludeMimes(java.lang.String[]);
method public void setImageToDefault();
method public void setMode(int);
+ method public void setOverlay(android.graphics.drawable.Drawable);
field protected java.lang.String[] mExcludeMimes;
}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 7df55a5..6b55b7b 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -749,6 +749,11 @@
"Error: Activity not started, you do not "
+ "have permission to access it.");
break;
+ case ActivityManager.START_NOT_VOICE_COMPATIBLE:
+ out.println(
+ "Error: Activity not started, voice control not allowed for: "
+ + intent);
+ break;
default:
out.println(
"Error: Activity not started, unknown error code " + res);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 859d83b..3481437 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -219,7 +219,7 @@
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
- LOG_ALWAYS_FATAL("app_process: Unable to deterimine ABI list from property %s.",
+ LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 41afa39..1780e03 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -51,6 +51,7 @@
#include "BootAnimation.h"
+#define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
#define EXIT_PROP_NAME "service.bootanim.exit"
@@ -283,6 +284,9 @@
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) ||
+ ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) &&
+ ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) ||
+
((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) {
mZip = zipFile;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 599a608..8981c88 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -22,6 +22,7 @@
import android.util.ArrayMap;
import android.util.SuperNotCalledException;
import android.widget.Toolbar;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.policy.PolicyManager;
@@ -726,6 +727,8 @@
/*package*/ ActionBar mActionBar = null;
private boolean mEnableDefaultActionBarUp;
+ private VoiceInteractor mVoiceInteractor;
+
private CharSequence mTitle;
private int mTitleColor = 0;
@@ -1134,6 +1137,23 @@
}
/**
+ * Check whether this activity is running as part of a voice interaction with the user.
+ * If true, it should perform its interaction with the user through the
+ * {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
+ */
+ public boolean isVoiceInteraction() {
+ return mVoiceInteractor != null;
+ }
+
+ /**
+ * Retrieve the active {@link VoiceInteractor} that the user is going through to
+ * interact with this activity.
+ */
+ public VoiceInteractor getVoiceInteractor() {
+ return mVoiceInteractor;
+ }
+
+ /**
* This is called for activities that set launchMode to "singleTop" in
* their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}
* flag when calling {@link #startActivity}. In either case, when the
@@ -5397,7 +5417,7 @@
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attach(context, aThread, instr, token, ident, application, intent, info, title, parent, id,
- lastNonConfigurationInstances, config, null);
+ lastNonConfigurationInstances, config, null, null);
}
final void attach(Context context, ActivityThread aThread,
@@ -5405,7 +5425,7 @@
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
- Configuration config, Bundle options) {
+ Configuration config, Bundle options, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
@@ -5433,6 +5453,8 @@
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
+ mVoiceInteractor = voiceInteractor != null
+ ? new VoiceInteractor(this, this, voiceInteractor, Looper.myLooper()) : null;
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c027e99..018e949 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -76,6 +76,13 @@
public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
/**
+ * Result for IActivityManager.startActivity: trying to start an activity under voice
+ * control when that activity does not support the VOICE category.
+ * @hide
+ */
+ public static final int START_NOT_VOICE_COMPATIBLE = -7;
+
+ /**
* Result for IActivityManager.startActivity: an error where the
* start had to be canceled.
* @hide
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 10831f2..b1c37de 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -43,9 +43,11 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
+import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
import android.util.Log;
import android.util.Singleton;
+import com.android.internal.app.IVoiceInteractor;
import java.util.ArrayList;
import java.util.List;
@@ -242,6 +244,33 @@
return true;
}
+ case START_VOICE_ACTIVITY_TRANSACTION:
+ {
+ data.enforceInterface(IActivityManager.descriptor);
+ String callingPackage = data.readString();
+ int callingPid = data.readInt();
+ int callingUid = data.readInt();
+ Intent intent = Intent.CREATOR.createFromParcel(data);
+ String resolvedType = data.readString();
+ IVoiceInteractionSession session = IVoiceInteractionSession.Stub.asInterface(
+ data.readStrongBinder());
+ IVoiceInteractor interactor = IVoiceInteractor.Stub.asInterface(
+ data.readStrongBinder());
+ int startFlags = data.readInt();
+ String profileFile = data.readString();
+ ParcelFileDescriptor profileFd = data.readInt() != 0
+ ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
+ Bundle options = data.readInt() != 0
+ ? Bundle.CREATOR.createFromParcel(data) : null;
+ int userId = data.readInt();
+ int result = startVoiceActivity(callingPackage, callingPid, callingUid,
+ intent, resolvedType, session, interactor, startFlags,
+ profileFile, profileFd, options, userId);
+ reply.writeNoException();
+ reply.writeInt(result);
+ return true;
+ }
+
case START_NEXT_MATCHING_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
@@ -2323,6 +2352,42 @@
data.recycle();
return result;
}
+ public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
+ Intent intent, String resolvedType, IVoiceInteractionSession session,
+ IVoiceInteractor interactor, int startFlags, String profileFile,
+ ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(callingPackage);
+ data.writeInt(callingPid);
+ data.writeInt(callingUid);
+ intent.writeToParcel(data, 0);
+ data.writeString(resolvedType);
+ data.writeStrongBinder(session.asBinder());
+ data.writeStrongBinder(interactor.asBinder());
+ data.writeInt(startFlags);
+ data.writeString(profileFile);
+ if (profileFd != null) {
+ data.writeInt(1);
+ profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ data.writeInt(0);
+ }
+ if (options != null) {
+ data.writeInt(1);
+ options.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ data.writeInt(userId);
+ mRemote.transact(START_VOICE_ACTIVITY_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int result = reply.readInt();
+ reply.recycle();
+ data.recycle();
+ return result;
+ }
public boolean startNextMatchingActivity(IBinder callingActivity,
Intent intent, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 88eae7f..7dc21b4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -94,6 +94,7 @@
import android.renderscript.RenderScript;
import android.security.AndroidKeyStoreProvider;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
@@ -265,6 +266,7 @@
IBinder token;
int ident;
Intent intent;
+ IVoiceInteractor voiceInteractor;
Bundle state;
Activity activity;
Window window;
@@ -603,6 +605,7 @@
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
+ IVoiceInteractor voiceInteractor,
int procState, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
@@ -615,6 +618,7 @@
r.token = token;
r.ident = ident;
r.intent = intent;
+ r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
@@ -2197,7 +2201,8 @@
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
- r.embeddedID, r.lastNonConfigurationInstances, config, options);
+ r.embeddedID, r.lastNonConfigurationInstances, config, options,
+ r.voiceInteractor);
if (customIntent != null) {
activity.mIntent = customIntent;
@@ -3003,7 +3008,9 @@
int h;
if (w < 0) {
Resources res = r.activity.getResources();
- if (SystemProperties.getBoolean("persist.recents.use_alternate", false)) {
+ Configuration config = res.getConfiguration();
+ boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
+ if (useAlternateRecents) {
int wId = com.android.internal.R.dimen.recents_thumbnail_width;
int hId = com.android.internal.R.dimen.recents_thumbnail_height;
mThumbnailWidth = w = res.getDimensionPixelSize(wId);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index edf21dd..a810134 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -147,6 +147,7 @@
if (mSurface != null) {
mActivityContainer.startActivity(intent);
} else {
+ mActivityContainer.checkEmbeddedAllowed(intent);
mQueuedIntent = intent;
mQueuedPendingIntent = null;
}
@@ -162,6 +163,7 @@
if (mSurface != null) {
mActivityContainer.startActivityIntentSender(iIntentSender);
} else {
+ mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
mQueuedPendingIntent = iIntentSender;
mQueuedIntent = null;
}
@@ -177,6 +179,7 @@
if (mSurface != null) {
mActivityContainer.startActivityIntentSender(iIntentSender);
} else {
+ mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
mQueuedPendingIntent = iIntentSender;
mQueuedIntent = null;
}
@@ -326,6 +329,24 @@
}
}
+ void checkEmbeddedAllowed(Intent intent) {
+ try {
+ mIActivityContainer.checkEmbeddedAllowed(intent);
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to startActivity from Intent. " + e);
+ }
+ }
+
+ void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
+ try {
+ mIActivityContainer.checkEmbeddedAllowedIntentSender(intentSender);
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to startActivity from IntentSender. " + e);
+ }
+ }
+
int getDisplayId() {
try {
return mIActivityContainer.getDisplayId();
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index f1c632e..fcc7f8e 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -33,6 +33,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import com.android.internal.app.IVoiceInteractor;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -136,6 +137,8 @@
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
+ IVoiceInteractor voiceInteractor = IVoiceInteractor.Stub.asInterface(
+ data.readStrongBinder());
int procState = data.readInt();
Bundle state = data.readBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
@@ -147,7 +150,8 @@
? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
boolean autoStopProfiler = data.readInt() != 0;
Bundle resumeArgs = data.readBundle();
- scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, procState, state,
+ scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo,
+ voiceInteractor, procState, state,
ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler,
resumeArgs);
return true;
@@ -735,6 +739,7 @@
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
+ IVoiceInteractor voiceInteractor,
int procState, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
@@ -748,6 +753,7 @@
info.writeToParcel(data, 0);
curConfig.writeToParcel(data, 0);
compatInfo.writeToParcel(data, 0);
+ data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
data.writeInt(procState);
data.writeBundle(state);
data.writeTypedList(pendingResults);
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index cc3b10c..52884f7 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -29,6 +29,8 @@
void setSurface(in Surface surface, int width, int height, int density);
int startActivity(in Intent intent);
int startActivityIntentSender(in IIntentSender intentSender);
+ void checkEmbeddedAllowed(in Intent intent);
+ void checkEmbeddedAllowedIntentSender(in IIntentSender intentSender);
int getDisplayId();
boolean injectEvent(in InputEvent event);
void release();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 52003f1..6b94c4e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -47,6 +47,8 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.service.voice.IVoiceInteractionSession;
+import com.android.internal.app.IVoiceInteractor;
import java.util.List;
@@ -77,6 +79,10 @@
IntentSender intent, Intent fillInIntent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues, Bundle options) throws RemoteException;
+ public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
+ Intent intent, String resolvedType, IVoiceInteractionSession session,
+ IVoiceInteractor interactor, int flags, String profileFile,
+ ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
public boolean startNextMatchingActivity(IBinder callingActivity,
Intent intent, Bundle options) throws RemoteException;
public boolean finishActivity(IBinder token, int code, Intent data, boolean finishTask)
@@ -733,4 +739,5 @@
int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
int SET_ACTIVITY_LABEL_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
+ int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index ac8ac8f..f290e94 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -31,6 +31,8 @@
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
+import android.service.voice.IVoiceInteractionSession;
+import com.android.internal.app.IVoiceInteractor;
import java.io.FileDescriptor;
import java.util.List;
@@ -55,8 +57,9 @@
void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- int procState, Bundle state, List<ResultInfo> pendingResults,
- List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+ IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed,
+ boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle resumeArgs)
throws RemoteException;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 8681f5c..ad4027d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -18,11 +18,15 @@
package android.app;
import android.app.ITransientNotification;
-import android.service.notification.StatusBarNotification;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Intent;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
+import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
/** {@hide} */
@@ -53,4 +57,7 @@
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config);
+ oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
+ oneway void requestZenModeConditions(in IConditionListener callback, boolean requested);
+ oneway void setZenModeCondition(in Uri conditionId);
}
\ No newline at end of file
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 028fa68..e58ccb8 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1428,7 +1428,7 @@
}
/**
- * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
+ * Like {@link #execStartActivity},
* but accepts an array of activities to be started. Note that active
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
@@ -1442,7 +1442,7 @@
}
/**
- * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
+ * Like {@link #execStartActivity},
* but accepts an array of activities to be started. Note that active
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
@@ -1545,8 +1545,7 @@
}
/**
- * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
- * but for starting as a particular user.
+ * Like {@link #execStartActivity}, but for starting as a particular user.
*
* @param who The Context from which the activity is being started.
* @param contextThread The main thread of the Context from which the activity
@@ -1616,7 +1615,8 @@
mUiAutomationConnection = uiAutomationConnection;
}
- /*package*/ static void checkStartActivityResult(int res, Object intent) {
+ /** @hide */
+ public static void checkStartActivityResult(int res, Object intent) {
if (res >= ActivityManager.START_SUCCESS) {
return;
}
@@ -1640,6 +1640,9 @@
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException(
"PendingIntent is not an activity");
+ case ActivityManager.START_NOT_VOICE_COMPATIBLE:
+ throw new SecurityException(
+ "Starting under voice control not allowed for: " + intent);
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index fe629f6..25a1493 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -328,8 +328,8 @@
/**
* Bit to be bitwise-ored into the {@link #flags} field that should be
- * set if you want the sound and/or vibration play each time the
- * notification is sent, even if it has not been canceled before that.
+ * set if you would only like the sound, vibrate and ticker to be played
+ * if the notification was not already showing.
*/
public static final int FLAG_ONLY_ALERT_ONCE = 0x00000008;
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 1b838fb..4427ce1 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -19,6 +19,9 @@
import android.content.SharedPreferences;
import android.os.FileUtils;
import android.os.Looper;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
import android.util.Log;
import com.google.android.collect.Maps;
@@ -43,10 +46,7 @@
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.StructStat;
final class SharedPreferencesImpl implements SharedPreferences {
private static final String TAG = "SharedPreferencesImpl";
@@ -110,7 +110,7 @@
Map map = null;
StructStat stat = null;
try {
- stat = Libcore.os.stat(mFile.getPath());
+ stat = Os.stat(mFile.getPath());
if (mFile.canRead()) {
BufferedInputStream str = null;
try {
@@ -172,7 +172,7 @@
* violation, but we explicitly want this one.
*/
BlockGuard.getThreadPolicy().onReadFromDisk();
- stat = Libcore.os.stat(mFile.getPath());
+ stat = Os.stat(mFile.getPath());
} catch (ErrnoException e) {
return true;
}
@@ -599,7 +599,7 @@
str.close();
ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
try {
- final StructStat stat = Libcore.os.stat(mFile.getPath());
+ final StructStat stat = Os.stat(mFile.getPath());
synchronized (this) {
mStatTimestamp = stat.st_mtime;
mStatSize = stat.st_size;
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
new file mode 100644
index 0000000..6dc48b0
--- /dev/null
+++ b/core/java/android/app/VoiceInteractor.java
@@ -0,0 +1,275 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.IVoiceInteractorCallback;
+import com.android.internal.app.IVoiceInteractorRequest;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+
+import java.util.WeakHashMap;
+
+/**
+ * Interface for an {@link Activity} to interact with the user through voice.
+ */
+public class VoiceInteractor {
+ static final String TAG = "VoiceInteractor";
+ static final boolean DEBUG = true;
+
+ final Context mContext;
+ final Activity mActivity;
+ final IVoiceInteractor mInteractor;
+ final HandlerCaller mHandlerCaller;
+ final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() {
+ @Override
+ public void executeMessage(Message msg) {
+ SomeArgs args = (SomeArgs)msg.obj;
+ Request request;
+ switch (msg.what) {
+ case MSG_CONFIRMATION_RESULT:
+ request = pullRequest((IVoiceInteractorRequest)args.arg1, true);
+ if (DEBUG) Log.d(TAG, "onConfirmResult: req="
+ + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
+ + " confirmed=" + msg.arg1 + " result=" + args.arg2);
+ if (request != null) {
+ ((ConfirmationRequest)request).onConfirmationResult(msg.arg1 != 0,
+ (Bundle) args.arg2);
+ request.clear();
+ }
+ break;
+ case MSG_COMMAND_RESULT:
+ request = pullRequest((IVoiceInteractorRequest)args.arg1, msg.arg1 != 0);
+ if (DEBUG) Log.d(TAG, "onCommandResult: req="
+ + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
+ + " result=" + args.arg2);
+ if (request != null) {
+ ((CommandRequest)request).onCommandResult((Bundle) args.arg2);
+ if (msg.arg1 != 0) {
+ request.clear();
+ }
+ }
+ break;
+ case MSG_CANCEL_RESULT:
+ request = pullRequest((IVoiceInteractorRequest)args.arg1, true);
+ if (DEBUG) Log.d(TAG, "onCancelResult: req="
+ + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request);
+ if (request != null) {
+ request.onCancel();
+ request.clear();
+ }
+ break;
+ }
+ }
+ };
+
+ final IVoiceInteractorCallback.Stub mCallback = new IVoiceInteractorCallback.Stub() {
+ @Override
+ public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed,
+ Bundle result) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(
+ MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, request, result));
+ }
+
+ @Override
+ public void deliverCommandResult(IVoiceInteractorRequest request, boolean complete,
+ Bundle result) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(
+ MSG_COMMAND_RESULT, complete ? 1 : 0, request, result));
+ }
+
+ @Override
+ public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(
+ MSG_CANCEL_RESULT, request));
+ }
+ };
+
+ final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+
+ static final int MSG_CONFIRMATION_RESULT = 1;
+ static final int MSG_COMMAND_RESULT = 2;
+ static final int MSG_CANCEL_RESULT = 3;
+
+ public static abstract class Request {
+ IVoiceInteractorRequest mRequestInterface;
+ Context mContext;
+ Activity mActivity;
+
+ public Request() {
+ }
+
+ public void cancel() {
+ try {
+ mRequestInterface.cancel();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Voice interactor has died", e);
+ }
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public Activity getActivity() {
+ return mActivity;
+ }
+
+ public void onCancel() {
+ }
+
+ void clear() {
+ mRequestInterface = null;
+ mContext = null;
+ mActivity = null;
+ }
+
+ abstract IVoiceInteractorRequest submit(IVoiceInteractor interactor,
+ String packageName, IVoiceInteractorCallback callback) throws RemoteException;
+ }
+
+ public static class ConfirmationRequest extends Request {
+ final CharSequence mPrompt;
+ final Bundle mExtras;
+
+ /**
+ * Confirms an operation with the user via the trusted system
+ * VoiceInteractionService. This allows an Activity to complete an unsafe operation that
+ * would require the user to touch the screen when voice interaction mode is not enabled.
+ * The result of the confirmation will be returned through an asynchronous call to
+ * either {@link #onConfirmationResult(boolean, android.os.Bundle)} or
+ * {@link #onCancel()}.
+ *
+ * <p>In some cases this may be a simple yes / no confirmation or the confirmation could
+ * include context information about how the action will be completed
+ * (e.g. booking a cab might include details about how long until the cab arrives)
+ * so the user can give a confirmation.
+ * @param prompt Optional confirmation text to read to the user as the action being
+ * confirmed.
+ * @param extras Additional optional information.
+ */
+ public ConfirmationRequest(CharSequence prompt, Bundle extras) {
+ mPrompt = prompt;
+ mExtras = extras;
+ }
+
+ public void onConfirmationResult(boolean confirmed, Bundle result) {
+ }
+
+ IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName,
+ IVoiceInteractorCallback callback) throws RemoteException {
+ return interactor.startConfirmation(packageName, callback, mPrompt.toString(), mExtras);
+ }
+ }
+
+ public static class CommandRequest extends Request {
+ final String mCommand;
+ final Bundle mArgs;
+
+ /**
+ * Execute a command using the trusted system VoiceInteractionService.
+ * This allows an Activity to request additional information from the user needed to
+ * complete an action (e.g. booking a table might have several possible times that the
+ * user could select from or an app might need the user to agree to a terms of service).
+ * The result of the confirmation will be returned through an asynchronous call to
+ * either {@link #onCommandResult(android.os.Bundle)} or
+ * {@link #onCancel()}.
+ *
+ * <p>The command is a string that describes the generic operation to be performed.
+ * The command will determine how the properties in extras are interpreted and the set of
+ * available commands is expected to grow over time. An example might be
+ * "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number of bags as part of
+ * airline check-in. (This is not an actual working example.)
+ *
+ * @param command The desired command to perform.
+ * @param args Additional arguments to control execution of the command.
+ */
+ public CommandRequest(String command, Bundle args) {
+ mCommand = command;
+ mArgs = args;
+ }
+
+ public void onCommandResult(Bundle result) {
+ }
+
+ IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName,
+ IVoiceInteractorCallback callback) throws RemoteException {
+ return interactor.startConfirmation(packageName, callback, mCommand, mArgs);
+ }
+ }
+
+ VoiceInteractor(Context context, Activity activity, IVoiceInteractor interactor,
+ Looper looper) {
+ mContext = context;
+ mActivity = activity;
+ mInteractor = interactor;
+ mHandlerCaller = new HandlerCaller(context, looper, mHandlerCallerCallback, true);
+ }
+
+ Request pullRequest(IVoiceInteractorRequest request, boolean complete) {
+ synchronized (mActiveRequests) {
+ Request req = mActiveRequests.get(request.asBinder());
+ if (req != null && complete) {
+ mActiveRequests.remove(request.asBinder());
+ }
+ return req;
+ }
+ }
+
+ public boolean submitRequest(Request request) {
+ try {
+ IVoiceInteractorRequest ireq = request.submit(mInteractor,
+ mContext.getOpPackageName(), mCallback);
+ request.mRequestInterface = ireq;
+ request.mContext = mContext;
+ request.mActivity = mActivity;
+ synchronized (mActiveRequests) {
+ mActiveRequests.put(ireq.asBinder(), request);
+ }
+ return true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remove voice interactor service died", e);
+ return false;
+ }
+ }
+
+ /**
+ * Queries the supported commands available from the VoiceinteractionService.
+ * The command is a string that describes the generic operation to be performed.
+ * An example might be "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number
+ * of bags as part of airline check-in. (This is not an actual working example.)
+ *
+ * @param commands
+ */
+ public boolean[] supportsCommands(String[] commands) {
+ try {
+ boolean[] res = mInteractor.supportsCommands(mContext.getOpPackageName(), commands);
+ if (DEBUG) Log.d(TAG, "supportsCommands: cmds=" + commands + " res=" + res);
+ return res;
+ } catch (RemoteException e) {
+ throw new RuntimeException("Voice interactor has died", e);
+ }
+ }
+}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index e6e0f35..5f8ebbe 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -44,10 +45,14 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Log;
import android.view.WindowManagerGlobal;
import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -65,6 +70,11 @@
private float mWallpaperXStep = -1;
private float mWallpaperYStep = -1;
+ /** {@hide} */
+ private static final String PROP_WALLPAPER = "ro.config.wallpaper";
+ /** {@hide} */
+ private static final String PROP_WALLPAPER_COMPONENT = "ro.config.wallpaper_component";
+
/**
* Activity Action: Show settings for choosing wallpaper. Do not use directly to construct
* an intent; instead, use {@link #getCropAndSetWallpaperIntent}.
@@ -269,13 +279,15 @@
}
private Bitmap getCurrentWallpaperLocked(Context context) {
+ if (mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return null;
+ }
+
try {
Bundle params = new Bundle();
ParcelFileDescriptor fd = mService.getWallpaper(this, params);
if (fd != null) {
- int width = params.getInt("width", 0);
- int height = params.getInt("height", 0);
-
try {
BitmapFactory.Options options = new BitmapFactory.Options();
return BitmapFactory.decodeFileDescriptor(
@@ -297,28 +309,20 @@
}
private Bitmap getDefaultWallpaperLocked(Context context) {
- try {
- InputStream is = context.getResources().openRawResource(
- com.android.internal.R.drawable.default_wallpaper);
- if (is != null) {
- int width = mService.getWidthHint();
- int height = mService.getHeightHint();
-
+ InputStream is = openDefaultWallpaper(context);
+ if (is != null) {
+ try {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ return BitmapFactory.decodeStream(is, null, options);
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Can't decode stream", e);
+ } finally {
try {
- BitmapFactory.Options options = new BitmapFactory.Options();
- return BitmapFactory.decodeStream(is, null, options);
- } catch (OutOfMemoryError e) {
- Log.w(TAG, "Can't decode stream", e);
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- // Ignore
- }
+ is.close();
+ } catch (IOException e) {
+ // Ignore
}
}
- } catch (RemoteException e) {
- // Ignore
}
return null;
}
@@ -403,8 +407,7 @@
horizontalAlignment = Math.max(0, Math.min(1, horizontalAlignment));
verticalAlignment = Math.max(0, Math.min(1, verticalAlignment));
- InputStream is = new BufferedInputStream(
- resources.openRawResource(com.android.internal.R.drawable.default_wallpaper));
+ InputStream is = new BufferedInputStream(openDefaultWallpaper(mContext));
if (is == null) {
Log.e(TAG, "default wallpaper input stream is null");
@@ -429,8 +432,7 @@
}
}
- is = new BufferedInputStream(resources.openRawResource(
- com.android.internal.R.drawable.default_wallpaper));
+ is = new BufferedInputStream(openDefaultWallpaper(mContext));
RectF cropRectF;
@@ -479,8 +481,7 @@
if (crop == null) {
// BitmapRegionDecoder has failed, try to crop in-memory
- is = new BufferedInputStream(resources.openRawResource(
- com.android.internal.R.drawable.default_wallpaper));
+ is = new BufferedInputStream(openDefaultWallpaper(mContext));
Bitmap fullSize = null;
if (is != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
@@ -1009,6 +1010,53 @@
* wallpaper.
*/
public void clear() throws IOException {
- setResource(com.android.internal.R.drawable.default_wallpaper);
+ setStream(openDefaultWallpaper(mContext));
+ }
+
+ /**
+ * Open stream representing the default static image wallpaper.
+ *
+ * @hide
+ */
+ public static InputStream openDefaultWallpaper(Context context) {
+ final String path = SystemProperties.get(PROP_WALLPAPER);
+ if (!TextUtils.isEmpty(path)) {
+ final File file = new File(path);
+ if (file.exists()) {
+ try {
+ return new FileInputStream(file);
+ } catch (IOException e) {
+ // Ignored, fall back to platform default below
+ }
+ }
+ }
+ return context.getResources().openRawResource(
+ com.android.internal.R.drawable.default_wallpaper);
+ }
+
+ /**
+ * Return {@link ComponentName} of the default live wallpaper, or
+ * {@code null} if none is defined.
+ *
+ * @hide
+ */
+ public static ComponentName getDefaultWallpaperComponent(Context context) {
+ String flat = SystemProperties.get(PROP_WALLPAPER_COMPONENT);
+ if (!TextUtils.isEmpty(flat)) {
+ final ComponentName cn = ComponentName.unflattenFromString(flat);
+ if (cn != null) {
+ return cn;
+ }
+ }
+
+ flat = context.getString(com.android.internal.R.string.default_wallpaper_component);
+ if (!TextUtils.isEmpty(flat)) {
+ final ComponentName cn = ComponentName.unflattenFromString(flat);
+ if (cn != null) {
+ return cn;
+ }
+ }
+
+ return null;
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index db08a41..68ab611 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -33,6 +33,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.service.trust.TrustAgentService;
import android.util.Log;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -1267,7 +1268,7 @@
public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0;
/**
- * Disable all keyguard widgets
+ * Disable all keyguard widgets. Has no effect.
*/
public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1 << 0;
@@ -1277,6 +1278,22 @@
public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 1 << 1;
/**
+ * Disable showing all notifications on secure keyguard screens (e.g. PIN/Pattern/Password)
+ */
+ public static final int KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 1 << 2;
+
+ /**
+ * Only allow redacted notifications on secure keyguard screens (e.g. PIN/Pattern/Password)
+ */
+ public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 1 << 3;
+
+ /**
+ * Ignore {@link TrustAgentService} state on secure keyguard screens
+ * (e.g. PIN/Pattern/Password).
+ */
+ public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 1 << 4;
+
+ /**
* Disable all current and future keyguard customizations.
*/
public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff;
@@ -1496,7 +1513,8 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param which {@link #KEYGUARD_DISABLE_FEATURES_NONE} (default),
* {@link #KEYGUARD_DISABLE_WIDGETS_ALL}, {@link #KEYGUARD_DISABLE_SECURE_CAMERA},
- * {@link #KEYGUARD_DISABLE_FEATURES_ALL}
+ * {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_TRUST_AGENTS},
+ * {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_FEATURES_ALL}
*/
public void setKeyguardDisabledFeatures(ComponentName admin, int which) {
if (mService != null) {
@@ -1816,6 +1834,27 @@
/**
* @hide
+ * @param userId the userId of a managed profile profile.
+ *
+ * @return whether or not the managed profile is enabled.
+ * @throws IllegalArgumentException if the userId is invalid.
+ */
+ public boolean isProfileEnabled(int userId) throws IllegalArgumentException {
+ if (mService != null) {
+ try {
+ return mService.isProfileEnabled(userId);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to get status for owner profile.");
+ throw new IllegalArgumentException(
+ "Failed to get status for owner profile.", re);
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * @hide
* @return the human readable name of the organisation associated with this DPM or null if
* one is not set.
* @throws IllegalArgumentException if the userId is invalid.
@@ -1936,4 +1975,48 @@
}
return null;
}
+
+ /**
+ * Called by a profile or device owner to set a user restriction specified
+ * by the key.
+ * <p>
+ * The calling device admin must be a profile or device owner; if it is not,
+ * a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param key The key of the restriction. See the constants in
+ * {@link android.os.UserManager} for the list of keys.
+ */
+ public void addUserRestriction(ComponentName admin, String key) {
+ if (mService != null) {
+ try {
+ mService.setUserRestriction(admin, key, true);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Called by a profile or device owner to clear a user restriction specified
+ * by the key.
+ * <p>
+ * The calling device admin must be a profile or device owner; if it is not,
+ * a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param key The key of the restriction. See the constants in
+ * {@link android.os.UserManager} for the list of keys.
+ */
+ public void clearUserRestriction(ComponentName admin, String key) {
+ if (mService != null) {
+ try {
+ mService.setUserRestriction(admin, key, false);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 4ed85e9..72b3c20 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -109,6 +109,7 @@
String getProfileOwner(int userHandle);
String getProfileOwnerName(int userHandle);
void setProfileEnabled(in ComponentName who);
+ boolean isProfileEnabled(int userHandle);
boolean installCaCert(in byte[] certBuffer);
void uninstallCaCert(in byte[] certBuffer);
@@ -118,4 +119,6 @@
void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings);
Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
+
+ void setUserRestriction(in ComponentName who, in String key, boolean enable);
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 3c31f8d..886f1a6 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -29,6 +29,10 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStat;
import android.util.Log;
import java.io.File;
@@ -38,11 +42,6 @@
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.OsConstants;
-import libcore.io.StructStat;
-
/**
* Provides the central interface between an
* application and Android's data backup infrastructure. An application that wishes
@@ -195,7 +194,7 @@
* the key supplied as part of the entity. Writing an entity with a negative
* data size instructs the transport to delete whatever entity currently exists
* under that key from the remote data set.
- *
+ *
* @param oldState An open, read-only ParcelFileDescriptor pointing to the
* last backup state provided by the application. May be
* <code>null</code>, in which case no prior state is being
@@ -226,7 +225,7 @@
* onRestore() throws an exception, the OS will assume that the
* application's data may now be in an incoherent state, and will clear it
* before proceeding.
- *
+ *
* @param data A structured wrapper around an open, read-only
* file descriptor pointing to a full snapshot of the
* application's data. The application should consume every
@@ -416,7 +415,7 @@
}
// If it's a directory, enqueue its contents for scanning.
- StructStat stat = Libcore.os.lstat(filePath);
+ StructStat stat = Os.lstat(filePath);
if (OsConstants.S_ISLNK(stat.st_mode)) {
if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
continue;
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index cfd0a65..6ebb6c4 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -17,6 +17,8 @@
package android.app.backup;
import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
import java.io.File;
@@ -24,9 +26,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-
/**
* Global constant definitions et cetera related to the full-backup-to-fd
* binary format. Nothing in this namespace is part of any API; it's all
@@ -147,7 +146,7 @@
try {
// explicitly prevent emplacement of files accessible by outside apps
mode &= 0700;
- Libcore.os.chmod(outFile.getPath(), (int)mode);
+ Os.chmod(outFile.getPath(), (int)mode);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index cbb6cf5..de223a3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2442,6 +2442,14 @@
public static final String APPWIDGET_SERVICE = "appwidget";
/**
+ * Official published name of the (internal) voice interaction manager service.
+ *
+ * @hide
+ * @see #getSystemService
+ */
+ public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction";
+
+ /**
* Use with {@link #getSystemService} to retrieve an
* {@link android.app.backup.IBackupManager IBackupManager} for communicating
* with the backup mechanism.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c0f04af..ae5437b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2804,6 +2804,14 @@
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
/**
+ * Categories for activities that can participate in voice interaction.
+ * An activity that supports this category must be prepared to run with
+ * no UI shown at all (though in some case it may have a UI shown), and
+ * rely on {@link android.app.VoiceInteractor} to interact with the user.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_VOICE = "android.intent.category.VOICE";
+ /**
* Set if the activity should be considered as an alternative action to
* the data the user is currently viewing. See also
* {@link #CATEGORY_SELECTED_ALTERNATIVE} for an alternative action that
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 9916476..c53e545 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -198,7 +198,7 @@
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
- * {@link android.R.attr#primaryUserOnly} attribute.
+ * android.R.attr#primaryUserOnly attribute.
*/
public static final int FLAG_PRIMARY_USER_ONLY = 0x20000000;
/**
@@ -210,6 +210,13 @@
*/
public static final int FLAG_SINGLE_USER = 0x40000000;
/**
+ * @hide Bit in {@link #flags}: If set, this activity may be launched into an
+ * owned ActivityContainer such as that within an ActivityView. If not set and
+ * this activity is launched into such a container a SecurityExcception will be
+ * thrown. Set from the {@link android.R.attr#allowEmbedded} attribute.
+ */
+ public static final int FLAG_ALLOW_EMBEDDED = 0x80000000;
+ /**
* Options that have been set in the activity declaration in the
* manifest.
* These include:
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ae0899f..488e25f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -74,6 +74,9 @@
ActivityInfo getActivityInfo(in ComponentName className, int flags, int userId);
+ boolean activitySupportsIntent(in ComponentName className, in Intent intent,
+ String resolvedType);
+
ActivityInfo getReceiverInfo(in ComponentName className, int flags, int userId);
ServiceInfo getServiceInfo(in ComponentName className, int flags, int userId);
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 92b9146..9087338 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -19,6 +19,8 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Bitmap.Config;
@@ -37,6 +39,8 @@
*/
public class LauncherActivityInfo {
private static final boolean DEBUG = false;
+ private static final String TAG = "LauncherActivityInfo";
+
private final PackageManager mPm;
private final UserManager mUm;
@@ -121,25 +125,42 @@
}
/**
+ * Returns the name for the acitivty from android:name in the manifest.
+ * @return the name from android:name for the acitivity.
+ */
+ public String getName() {
+ return mActivityInfo.name;
+ }
+
+ /**
* Returns the activity icon with badging appropriate for the profile.
* @param density Optional density for the icon, or 0 to use the default density.
* @return A badged icon for the activity.
*/
public Drawable getBadgedIcon(int density) {
- // TODO: Handle density
- if (mUser.equals(android.os.Process.myUserHandle())) {
- return mActivityInfo.loadIcon(mPm);
- }
- Drawable originalIcon = mActivityInfo.loadIcon(mPm);
- if (originalIcon == null) {
- if (DEBUG) {
- Log.w("LauncherActivityInfo", "Couldn't find icon for activity");
+ int iconRes = mActivityInfo.getIconResource();
+ Resources resources = null;
+ Drawable originalIcon = null;
+ try {
+ resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
+ try {
+ if (density != 0) {
+ originalIcon = resources.getDrawableForDensity(iconRes, density);
+ }
+ } catch (Resources.NotFoundException e) {
}
- originalIcon = mPm.getDefaultActivityIcon();
+ } catch (NameNotFoundException nnfe) {
}
+
+ if (originalIcon == null) {
+ originalIcon = mActivityInfo.loadIcon(mPm);
+ }
+
if (originalIcon instanceof BitmapDrawable) {
return mUm.getBadgedDrawableForUser(
originalIcon, mUser);
+ } else {
+ Log.e(TAG, "Unable to create badged icon for " + mActivityInfo);
}
return originalIcon;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d981cc1..484a2a1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1235,7 +1235,6 @@
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
-
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports app widgets.
@@ -1244,6 +1243,17 @@
public static final String FEATURE_APP_WIDGETS = "android.software.app_widgets";
/**
+ * @hide
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports
+ * {@link android.service.voice.VoiceInteractionService} and
+ * {@link android.app.VoiceInteractor}.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VOICE_RECOGNIZERS = "android.software.voice_recognizers";
+
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports a home screen that is replaceable
* by third party applications.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8d8d220..8f19f01 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -50,6 +50,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
@@ -147,8 +148,7 @@
private String[] mSeparateProcesses;
private boolean mOnlyCoreApps;
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
- private static final String SDK_CODENAME = "REL".equals(Build.VERSION.CODENAME)
- ? null : Build.VERSION.CODENAME;
+ private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
private int mParseError = PackageManager.INSTALL_SUCCEEDED;
@@ -1200,10 +1200,18 @@
sa.recycle();
if (minCode != null) {
- if (!minCode.equals(SDK_CODENAME)) {
- if (SDK_CODENAME != null) {
+ boolean allowedCodename = false;
+ for (String codename : SDK_CODENAMES) {
+ if (minCode.equals(codename)) {
+ allowedCodename = true;
+ break;
+ }
+ }
+ if (!allowedCodename) {
+ if (SDK_CODENAMES.length > 0) {
outError[0] = "Requires development platform " + minCode
- + " (current platform is " + SDK_CODENAME + ")";
+ + " (current platform is any of "
+ + Arrays.toString(SDK_CODENAMES) + ")";
} else {
outError[0] = "Requires development platform " + minCode
+ " but this is a release platform.";
@@ -1219,10 +1227,18 @@
}
if (targetCode != null) {
- if (!targetCode.equals(SDK_CODENAME)) {
- if (SDK_CODENAME != null) {
+ boolean allowedCodename = false;
+ for (String codename : SDK_CODENAMES) {
+ if (targetCode.equals(codename)) {
+ allowedCodename = true;
+ break;
+ }
+ }
+ if (!allowedCodename) {
+ if (SDK_CODENAMES.length > 0) {
outError[0] = "Requires development platform " + targetCode
- + " (current platform is " + SDK_CODENAME + ")";
+ + " (current platform is any of "
+ + Arrays.toString(SDK_CODENAMES) + ")";
} else {
outError[0] = "Requires development platform " + targetCode
+ " but this is a release platform.";
@@ -2452,6 +2468,12 @@
a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+ }
+
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java
index cece556..e24aeb2 100644
--- a/core/java/android/ddm/DdmHandleHeap.java
+++ b/core/java/android/ddm/DdmHandleHeap.java
@@ -219,7 +219,7 @@
if (false)
Log.d("ddm-heap", "Heap GC request");
- System.gc();
+ Runtime.getRuntime().gc();
return null; // empty response
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index ee2adac..40a7905 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -157,7 +157,14 @@
mCameraId = cameraId;
mDeviceListener = listener;
mDeviceHandler = handler;
- TAG = String.format("CameraDevice-%s-JV", mCameraId);
+
+ final int MAX_TAG_LEN = 23;
+ String tag = String.format("CameraDevice-JV-%s", mCameraId);
+ if (tag.length() > MAX_TAG_LEN) {
+ tag = tag.substring(0, MAX_TAG_LEN);
+ }
+ TAG = tag;
+
DEBUG = Log.isLoggable(TAG, Log.DEBUG);
}
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index 21de9f5..4c074e9 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -79,7 +79,7 @@
*/
public static final int MONITOR_UNSUPPORTED = 2;
- // The following constants need to match geofence flags in gps.h
+ // The following constants need to match geofence flags in gps.h and fused_location.h
/**
* The constant to indicate that the user has entered the geofence.
*/
@@ -92,7 +92,7 @@
/**
* The constant to indicate that the user is uncertain with respect to a
- * geofence. nn
+ * geofence.
*/
public static final int GEOFENCE_UNCERTAIN = 1<<2L;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c51d1a7..505ef9c 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -255,7 +255,9 @@
public static final int CURSOR_ANCHOR_MONITOR_MODE_NONE = 0x0;
/**
- * The IME expects that {@link #onUpdateCursor(Rect)} is called back.
+ * Passing this flag into a call to {@link #setCursorAnchorMonitorMode(int)} will result in
+ * the cursor rectangle being provided in screen coordinates to subsequent
+ * {@link #onUpdateCursor(Rect)} callbacks.
*/
public static final int CURSOR_ANCHOR_MONITOR_MODE_CURSOR_RECT = 0x1;
@@ -1703,9 +1705,11 @@
}
/**
- * Called when the application has reported a new location of its text
- * cursor. This is only called if explicitly requested by the input method.
- * The default implementation does nothing.
+ * Called when the application has reported a new location of its text cursor. This is only
+ * called if explicitly requested by the input method. The default implementation does nothing.
+ * @param newCursor The new cursor position, in screen coordinates if the input method calls
+ * {@link #setCursorAnchorMonitorMode} with {@link #CURSOR_ANCHOR_MONITOR_MODE_CURSOR_RECT}.
+ * Otherwise, this is in local coordinates.
*/
public void onUpdateCursor(Rect newCursor) {
// Intentionally empty
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 22543e3..a725bec 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -24,13 +24,13 @@
import java.net.InterfaceAddress;
import java.net.UnknownHostException;
-import static libcore.io.OsConstants.IFA_F_DADFAILED;
-import static libcore.io.OsConstants.IFA_F_DEPRECATED;
-import static libcore.io.OsConstants.IFA_F_TENTATIVE;
-import static libcore.io.OsConstants.RT_SCOPE_HOST;
-import static libcore.io.OsConstants.RT_SCOPE_LINK;
-import static libcore.io.OsConstants.RT_SCOPE_SITE;
-import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE;
+import static android.system.OsConstants.IFA_F_DADFAILED;
+import static android.system.OsConstants.IFA_F_DEPRECATED;
+import static android.system.OsConstants.IFA_F_TENTATIVE;
+import static android.system.OsConstants.RT_SCOPE_HOST;
+import static android.system.OsConstants.RT_SCOPE_LINK;
+import static android.system.OsConstants.RT_SCOPE_SITE;
+import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
/**
* Identifies an IP address on a network link.
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index 119e533..643e8c2 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -22,9 +22,9 @@
import java.io.FileDescriptor;
import java.net.SocketOptions;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.OsConstants;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
/**
* Socket implementation used for android.net.LocalSocket and
@@ -248,7 +248,7 @@
throw new IllegalStateException("unknown sockType");
}
try {
- fd = Libcore.os.socket(OsConstants.AF_UNIX, osType, 0);
+ fd = Os.socket(OsConstants.AF_UNIX, osType, 0);
mFdCreatedInternally = true;
} catch (ErrnoException e) {
e.rethrowAsIOException();
@@ -268,7 +268,7 @@
return;
}
try {
- Libcore.os.close(fd);
+ Os.close(fd);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 5e61613..6dd56d9 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -40,33 +40,33 @@
* and (eventually) calls {@link #updateScores} with the results.
* </ul>
*
- * <p>The system keeps track of a default scorer application; at any time, only this application
+ * <p>The system keeps track of an active scorer application; at any time, only this application
* will receive {@link #ACTION_SCORE_NETWORKS} broadcasts and will be permitted to call
- * {@link #updateScores}. Applications may determine the current default scorer with
- * {@link #getActiveScorerPackage()} and request to change the default scorer by sending an
- * {@link #ACTION_CHANGE_DEFAULT} broadcast with another scorer.
+ * {@link #updateScores}. Applications may determine the current active scorer with
+ * {@link #getActiveScorerPackage()} and request to change the active scorer by sending an
+ * {@link #ACTION_CHANGE_ACTIVE} broadcast with another scorer.
*
* @hide
*/
public class NetworkScoreManager {
/**
- * Activity action: ask the user to change the default network scorer. This will show a dialog
- * that asks the user whether they want to replace the current default scorer with the one
+ * Activity action: ask the user to change the active network scorer. This will show a dialog
+ * that asks the user whether they want to replace the current active scorer with the one
* specified in {@link #EXTRA_PACKAGE_NAME}. The activity will finish with RESULT_OK if the
- * default was changed or RESULT_CANCELED if it failed for any reason.
+ * active scorer was changed or RESULT_CANCELED if it failed for any reason.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_CHANGE_DEFAULT = "android.net.scoring.CHANGE_DEFAULT";
+ public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
/**
- * Extra used with {@link #ACTION_CHANGE_DEFAULT} to specify the new scorer package. Set with
+ * Extra used with {@link #ACTION_CHANGE_ACTIVE} to specify the new scorer package. Set with
* {@link android.content.Intent#putExtra(String, String)}.
*/
public static final String EXTRA_PACKAGE_NAME = "packageName";
/**
* Broadcast action: new network scores are being requested. This intent will only be delivered
- * to the current default scorer app. That app is responsible for scoring the networks and
+ * to the current active scorer app. That app is responsible for scoring the networks and
* calling {@link #updateScores} when complete. The networks to score are specified in
* {@link #EXTRA_NETWORKS_TO_SCORE}, and will generally consist of all networks which have been
* configured by the user as well as any open networks.
@@ -99,7 +99,7 @@
* <p>At any time, only one scorer application will receive {@link #ACTION_SCORE_NETWORKS}
* broadcasts and be allowed to call {@link #updateScores}. Applications may use this method to
* determine the current scorer and offer the user the ability to select a different scorer via
- * the {@link #ACTION_CHANGE_DEFAULT} intent.
+ * the {@link #ACTION_CHANGE_ACTIVE} intent.
* @return the full package name of the current active scorer, or null if there is no active
* scorer.
*/
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 726208a..3660e7a 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -97,8 +97,7 @@
public static String getActiveScorer(Context context) {
String scorerPackage = Settings.Global.getString(context.getContentResolver(),
Global.NETWORK_SCORER_APP);
- Collection<String> applications = getAllValidScorers(context);
- if (isPackageValidScorer(applications, scorerPackage)) {
+ if (isPackageValidScorer(context, scorerPackage)) {
return scorerPackage;
} else {
return null;
@@ -131,8 +130,7 @@
return true;
} else {
// We only make the change if the new package is valid.
- Collection<String> applications = getAllValidScorers(context);
- if (isPackageValidScorer(applications, packageName)) {
+ if (isPackageValidScorer(context, packageName)) {
Settings.Global.putString(context.getContentResolver(),
Settings.Global.NETWORK_SCORER_APP, packageName);
return true;
@@ -159,8 +157,8 @@
}
/** Returns true if the given package is a valid scorer. */
- private static boolean isPackageValidScorer(Collection<String> scorerPackageNames,
- String packageName) {
- return packageName != null && scorerPackageNames.contains(packageName);
+ public static boolean isPackageValidScorer(Context context, String packageName) {
+ Collection<String> applications = getAllValidScorers(context);
+ return packageName != null && applications.contains(packageName);
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e640649..f05ddde 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -130,8 +130,8 @@
// NOTE: Update this list if you add/change any stats above.
// These characters are supposed to represent "total", "last", "current",
// and "unplugged". They were shortened for efficiency sake.
- private static final String[] STAT_NAMES = { "t", "l", "c", "u" };
-
+ private static final String[] STAT_NAMES = { "l", "c", "u" };
+
/**
* Bump the version on this if the checkin format changes.
*/
@@ -186,7 +186,7 @@
* Returns the count associated with this Counter for the
* selected type of statistics.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
*/
public abstract int getCountLocked(int which);
@@ -205,7 +205,7 @@
* Returns the count associated with this Counter for the
* selected type of statistics.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
*/
public abstract long getCountLocked(int which);
@@ -224,7 +224,7 @@
* Returns the count associated with this Timer for the
* selected type of statistics.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
*/
public abstract int getCountLocked(int which);
@@ -233,7 +233,7 @@
* selected type of statistics.
*
* @param elapsedRealtimeUs current elapsed realtime of system in microseconds
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
* @return a time in microseconds
*/
public abstract long getTotalTimeLocked(long elapsedRealtimeUs, int which);
@@ -385,27 +385,27 @@
/**
* Returns the total time (in 1/100 sec) spent executing in user code.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long getUserTime(int which);
/**
* Returns the total time (in 1/100 sec) spent executing in system code.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long getSystemTime(int which);
/**
* Returns the number of times the process has been started.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract int getStarts(int which);
/**
* Returns the cpu time spent in microseconds while the process was in the foreground.
- * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @return foreground cpu time in microseconds
*/
public abstract long getForegroundTime(int which);
@@ -414,7 +414,7 @@
* Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
* @param speedStep the index of the CPU speed. This is not the actual speed of the
* CPU.
- * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @see BatteryStats#getCpuSpeedSteps()
*/
public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
@@ -433,7 +433,7 @@
* Returns the number of times this package has done something that could wake up the
* device from sleep.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract int getWakeups(int which);
@@ -451,7 +451,7 @@
* Returns the amount of time spent started.
*
* @param batteryUptime elapsed uptime on battery in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @return
*/
public abstract long getStartTime(long batteryUptime, int which);
@@ -459,14 +459,14 @@
/**
* Returns the total number of times startService() has been called.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract int getStarts(int which);
/**
* Returns the total number times the service has been launched.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract int getLaunches(int which);
}
@@ -1285,7 +1285,7 @@
* Returns the total, last, or current battery uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeBatteryUptime(long curTime, int which);
@@ -1293,7 +1293,7 @@
* Returns the total, last, or current battery realtime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeBatteryRealtime(long curTime, int which);
@@ -1301,7 +1301,7 @@
* Returns the total, last, or current battery screen off uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeBatteryScreenOffUptime(long curTime, int which);
@@ -1309,7 +1309,7 @@
* Returns the total, last, or current battery screen off realtime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeBatteryScreenOffRealtime(long curTime, int which);
@@ -1317,18 +1317,38 @@
* Returns the total, last, or current uptime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeUptime(long curTime, int which);
/**
* Returns the total, last, or current realtime in microseconds.
- * *
+ *
* @param curTime the current elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeRealtime(long curTime, int which);
-
+
+ /**
+ * Compute an approximation for how much run time (in microseconds) is remaining on
+ * the battery. Returns -1 if no time can be computed: either there is not
+ * enough current data to make a decision, or the battery is currently
+ * charging.
+ *
+ * @param curTime The current elepsed realtime in microseconds.
+ */
+ public abstract long computeBatteryTimeRemaining(long curTime);
+
+ /**
+ * Compute an approximation for how much time (in microseconds) remains until the battery
+ * is fully charged. Returns -1 if no time can be computed: either there is not
+ * enough current data to make a decision, or the battery is currently
+ * discharging.
+ *
+ * @param curTime The current elepsed realtime in microseconds.
+ */
+ public abstract long computeChargeTimeRemaining(long curTime);
+
public abstract Map<String, ? extends LongCounter> getWakeupReasonStats();
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
@@ -1430,7 +1450,7 @@
* @param timer a Timer object contining the wakelock times.
* @param elapsedRealtimeUs the current on-battery time in microseconds.
* @param name the name of the wakelock.
- * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @param linePrefix a String to be prepended to each line of output.
* @return the line prefix
*/
@@ -1464,7 +1484,7 @@
* @param timer a Timer object contining the wakelock times.
* @param elapsedRealtimeUs the current time in microseconds.
* @param name the name of the wakelock.
- * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @param linePrefix a String to be prepended to each line of output.
* @return the line prefix
*/
@@ -1682,7 +1702,7 @@
}
}
- BatteryStatsHelper helper = new BatteryStatsHelper(context);
+ BatteryStatsHelper helper = new BatteryStatsHelper(context, false);
helper.create(this);
helper.refreshStats(which, UserHandle.USER_ALL);
List<BatterySipper> sippers = helper.getUsageList();
@@ -1929,6 +1949,8 @@
final long whichBatteryScreenOffUptime = computeBatteryScreenOffUptime(rawUptime, which);
final long whichBatteryScreenOffRealtime = computeBatteryScreenOffRealtime(rawRealtime,
which);
+ final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime);
+ final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime);
StringBuilder sb = new StringBuilder(128);
@@ -1963,7 +1985,20 @@
sb.append("realtime, ");
formatTimeMs(sb, totalUptime / 1000);
sb.append("uptime");
- pw.println(sb.toString());
+ if (batteryTimeRemaining >= 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Battery time remaining: ");
+ formatTimeMs(sb, batteryTimeRemaining / 1000);
+ pw.println(sb.toString());
+ }
+ if (chargeTimeRemaining >= 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Charge time remaining: ");
+ formatTimeMs(sb, chargeTimeRemaining / 1000);
+ pw.println(sb.toString());
+ }
pw.print(" Start clock time: ");
pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
@@ -2268,7 +2303,7 @@
pw.println();
}
- BatteryStatsHelper helper = new BatteryStatsHelper(context);
+ BatteryStatsHelper helper = new BatteryStatsHelper(context, false);
helper.create(this);
helper.refreshStats(which, UserHandle.USER_ALL);
List<BatterySipper> sippers = helper.getUsageList();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 19be2c8..0336dd6 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -16,12 +16,17 @@
package android.os;
+import android.text.TextUtils;
+import android.util.Slog;
+
import com.android.internal.telephony.TelephonyProperties;
/**
* Information about the current build, extracted from system properties.
*/
public class Build {
+ private static final String TAG = "Build";
+
/** Value used for when a build property is unknown. */
public static final String UNKNOWN = "unknown";
@@ -118,14 +123,22 @@
*/
public static final String CODENAME = getString("ro.build.version.codename");
+ private static final String[] ALL_CODENAMES
+ = getString("ro.build.version.all_codenames").split(",");
+
/**
- * The SDK version to use when accessing resources.
- * Use the current SDK version code. If we are a development build,
- * also allow the previous SDK version + 1.
* @hide
*/
- public static final int RESOURCES_SDK_INT = SDK_INT
- + ("REL".equals(CODENAME) ? 0 : 1);
+ public static final String[] ACTIVE_CODENAMES = "REL".equals(ALL_CODENAMES[0])
+ ? new String[0] : ALL_CODENAMES;
+
+ /**
+ * The SDK version to use when accessing resources.
+ * Use the current SDK version code. For every active development codename
+ * we are operating under, we bump the assumed resource platform version by 1.
+ * @hide
+ */
+ public static final int RESOURCES_SDK_INT = SDK_INT + ACTIVE_CODENAMES.length;
}
/**
@@ -501,7 +514,43 @@
public static final String TAGS = getString("ro.build.tags");
/** A string that uniquely identifies this build. Do not attempt to parse this value. */
- public static final String FINGERPRINT = getString("ro.build.fingerprint");
+ public static final String FINGERPRINT = deriveFingerprint();
+
+ /**
+ * Some devices split the fingerprint components between multiple
+ * partitions, so we might derive the fingerprint at runtime.
+ */
+ private static String deriveFingerprint() {
+ String finger = SystemProperties.get("ro.build.fingerprint");
+ if (TextUtils.isEmpty(finger)) {
+ finger = getString("ro.product.brand") + '/' +
+ getString("ro.product.name") + '/' +
+ getString("ro.product.device") + ':' +
+ getString("ro.build.version.release") + '/' +
+ getString("ro.build.id") + '/' +
+ getString("ro.build.version.incremental") + ':' +
+ getString("ro.build.type") + '/' +
+ getString("ro.build.tags");
+ }
+ return finger;
+ }
+
+ /**
+ * Ensure that raw fingerprint system property is defined. If it was derived
+ * dynamically by {@link #deriveFingerprint()} this is where we push the
+ * derived value into the property service.
+ *
+ * @hide
+ */
+ public static void ensureFingerprintProperty() {
+ if (TextUtils.isEmpty(SystemProperties.get("ro.build.fingerprint"))) {
+ try {
+ SystemProperties.set("ro.build.fingerprint", FINGERPRINT);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Failed to set fingerprint property", e);
+ }
+ }
+ }
// The following properties only make sense for internal engineering builds.
public static final long TIME = getLong("ro.build.date.utc") * 1000;
diff --git a/core/java/android/os/CommonClock.java b/core/java/android/os/CommonClock.java
index 2ecf317..f83a90b 100644
--- a/core/java/android/os/CommonClock.java
+++ b/core/java/android/os/CommonClock.java
@@ -23,6 +23,7 @@
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
+import static android.system.OsConstants.*;
/**
* Used for accessing the android common time service's common clock and receiving notifications
diff --git a/core/java/android/os/CommonTimeUtils.java b/core/java/android/os/CommonTimeUtils.java
index 20755d9..ba060b8 100644
--- a/core/java/android/os/CommonTimeUtils.java
+++ b/core/java/android/os/CommonTimeUtils.java
@@ -20,7 +20,7 @@
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.util.Locale;
-import static libcore.io.OsConstants.*;
+import static android.system.OsConstants.*;
class CommonTimeUtils {
/**
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 1089f27..d71c3e6 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,12 +16,12 @@
package android.os;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.Log;
import android.util.Slog;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -85,7 +85,7 @@
*/
public static int setPermissions(String path, int mode, int uid, int gid) {
try {
- Libcore.os.chmod(path, mode);
+ Os.chmod(path, mode);
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to chmod(" + path + "): " + e);
return e.errno;
@@ -93,7 +93,7 @@
if (uid >= 0 || gid >= 0) {
try {
- Libcore.os.chown(path, uid, gid);
+ Os.chown(path, uid, gid);
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to chown(" + path + "): " + e);
return e.errno;
@@ -113,7 +113,7 @@
*/
public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) {
try {
- Libcore.os.fchmod(fd, mode);
+ Os.fchmod(fd, mode);
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to fchmod(): " + e);
return e.errno;
@@ -121,7 +121,7 @@
if (uid >= 0 || gid >= 0) {
try {
- Libcore.os.fchown(fd, uid, gid);
+ Os.fchown(fd, uid, gid);
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to fchown(): " + e);
return e.errno;
@@ -136,7 +136,7 @@
*/
public static int getUid(String path) {
try {
- return Libcore.os.stat(path).st_uid;
+ return Os.stat(path).st_uid;
} catch (ErrnoException e) {
return -1;
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 1192a45..c3f7370 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -34,7 +34,7 @@
void setUserIcon(int userHandle, in Bitmap icon);
Bitmap getUserIcon(int userHandle);
List<UserInfo> getUsers(boolean excludeDying);
- List<UserInfo> getProfiles(int userHandle);
+ List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
UserInfo getUserInfo(int userHandle);
boolean isRestricted();
void setGuestEnabled(boolean enable);
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 24bf05e..c6b2151 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -16,24 +16,24 @@
package android.os;
-import static libcore.io.OsConstants.AF_UNIX;
-import static libcore.io.OsConstants.SEEK_SET;
-import static libcore.io.OsConstants.SOCK_STREAM;
-import static libcore.io.OsConstants.S_ISLNK;
-import static libcore.io.OsConstants.S_ISREG;
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.SEEK_SET;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.S_ISLNK;
+import static android.system.OsConstants.S_ISREG;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStat;
import android.util.Log;
import dalvik.system.CloseGuard;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import libcore.io.Memory;
-import libcore.io.OsConstants;
-import libcore.io.StructStat;
import java.io.Closeable;
import java.io.File;
@@ -261,7 +261,7 @@
*/
public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
try {
- final FileDescriptor fd = Libcore.os.dup(orig);
+ final FileDescriptor fd = Os.dup(orig);
return new ParcelFileDescriptor(fd);
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
@@ -297,7 +297,7 @@
original.setInt$(fd);
try {
- final FileDescriptor dup = Libcore.os.dup(original);
+ final FileDescriptor dup = Os.dup(original);
return new ParcelFileDescriptor(dup);
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
@@ -359,7 +359,7 @@
*/
public static ParcelFileDescriptor[] createPipe() throws IOException {
try {
- final FileDescriptor[] fds = Libcore.os.pipe();
+ final FileDescriptor[] fds = Os.pipe();
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fds[0]),
new ParcelFileDescriptor(fds[1]) };
@@ -381,7 +381,7 @@
public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
try {
final FileDescriptor[] comm = createCommSocketPair();
- final FileDescriptor[] fds = Libcore.os.pipe();
+ final FileDescriptor[] fds = Os.pipe();
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fds[0], comm[0]),
new ParcelFileDescriptor(fds[1], comm[1]) };
@@ -398,7 +398,7 @@
try {
final FileDescriptor fd0 = new FileDescriptor();
final FileDescriptor fd1 = new FileDescriptor();
- Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fd0),
new ParcelFileDescriptor(fd1) };
@@ -421,7 +421,7 @@
final FileDescriptor[] comm = createCommSocketPair();
final FileDescriptor fd0 = new FileDescriptor();
final FileDescriptor fd1 = new FileDescriptor();
- Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fd0, comm[0]),
new ParcelFileDescriptor(fd1, comm[1]) };
@@ -434,7 +434,7 @@
try {
final FileDescriptor comm1 = new FileDescriptor();
final FileDescriptor comm2 = new FileDescriptor();
- Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
IoUtils.setBlocking(comm1, false);
IoUtils.setBlocking(comm2, false);
return new FileDescriptor[] { comm1, comm2 };
@@ -520,7 +520,7 @@
return mWrapped.getStatSize();
} else {
try {
- final StructStat st = Libcore.os.fstat(mFd);
+ final StructStat st = Os.fstat(mFd);
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
return st.st_size;
} else {
@@ -543,7 +543,7 @@
return mWrapped.seekTo(pos);
} else {
try {
- return Libcore.os.lseek(mFd, pos, SEEK_SET);
+ return Os.lseek(mFd, pos, SEEK_SET);
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
}
@@ -695,7 +695,7 @@
writePtr += len;
}
- Libcore.os.write(mCommFd, buf, 0, writePtr);
+ Os.write(mCommFd, buf, 0, writePtr);
} catch (ErrnoException e) {
// Reporting status is best-effort
Log.w(TAG, "Failed to report status: " + e);
@@ -712,7 +712,7 @@
private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
try {
- final int n = Libcore.os.read(comm, buf, 0, buf.length);
+ final int n = Os.read(comm, buf, 0, buf.length);
if (n == 0) {
// EOF means they're dead
return new Status(Status.DEAD);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 995e396..b4ed68c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -18,6 +18,7 @@
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
+import android.system.Os;
import android.util.Log;
import com.android.internal.os.Zygote;
import java.io.BufferedWriter;
@@ -28,7 +29,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import libcore.io.Libcore;
/*package*/ class ZygoteStartFailedEx extends Exception {
/**
@@ -741,7 +741,7 @@
* {@link #killProcess} and {@link #sendSignal}.
*/
public static final int myPid() {
- return Libcore.os.getpid();
+ return Os.getpid();
}
/**
@@ -749,7 +749,7 @@
* @hide
*/
public static final int myPpid() {
- return Libcore.os.getppid();
+ return Os.getppid();
}
/**
@@ -757,7 +757,7 @@
* {@link #setThreadPriority(int, int)}.
*/
public static final int myTid() {
- return Libcore.os.gettid();
+ return Os.gettid();
}
/**
@@ -767,7 +767,7 @@
* a uid identifies a specific app sandbox in a specific user.
*/
public static final int myUid() {
- return Libcore.os.getuid();
+ return Os.getuid();
}
/**
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index f671ed9..cdde4c7 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -375,6 +375,7 @@
final ConditionVariable condition = new ConditionVariable();
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java
index 9e9521a..13e9a15 100644
--- a/core/java/android/os/StatFs.java
+++ b/core/java/android/os/StatFs.java
@@ -16,9 +16,9 @@
package android.os;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.StructStatVfs;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStatVfs;
/**
* Retrieve overall information about the space on a filesystem. This is a
@@ -41,7 +41,7 @@
private static StructStatVfs doStat(String path) {
try {
- return Libcore.os.statvfs(path);
+ return Os.statvfs(path);
} catch (ErrnoException e) {
throw new IllegalArgumentException("Invalid path: " + path, e);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7bac3af..1fe9337 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -300,8 +300,7 @@
/**
* Sets all the user-wide restrictions for this user.
- * Requires the MANAGE_USERS permission or profile/device owner
- * privileges.
+ * Requires the MANAGE_USERS permission.
* @param restrictions the Bundle containing all the restrictions.
*/
public void setUserRestrictions(Bundle restrictions) {
@@ -310,8 +309,7 @@
/**
* Sets all the user-wide restrictions for the specified user.
- * Requires the MANAGE_USERS permission or profile/device owner
- * privileges.
+ * Requires the MANAGE_USERS permission.
* @param restrictions the Bundle containing all the restrictions.
* @param userHandle the UserHandle of the user for whom to set the restrictions.
*/
@@ -325,8 +323,7 @@
/**
* Sets the value of a specific restriction.
- * Requires the MANAGE_USERS permission or profile/device owner
- * privileges.
+ * Requires the MANAGE_USERS permission.
* @param key the key of the restriction
* @param value the value for the restriction
*/
@@ -339,8 +336,7 @@
/**
* @hide
* Sets the value of a specific restriction on a specific user.
- * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission or profile/device owner
- * privileges.
+ * Requires the MANAGE_USERS permission.
* @param key the key of the restriction
* @param value the value for the restriction
* @param userHandle the user whose restriction is to be changed.
@@ -466,6 +462,8 @@
/**
* Returns list of the profiles of userHandle including
* userHandle itself.
+ * Note that it this returns both enabled and not enabled profiles. See
+ * {@link #getUserProfiles()} if you need only the enabled ones.
*
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userHandle profiles of this user will be returned.
@@ -474,7 +472,7 @@
*/
public List<UserInfo> getProfiles(int userHandle) {
try {
- return mService.getProfiles(userHandle);
+ return mService.getProfiles(userHandle, false /* enabledOnly */);
} catch (RemoteException re) {
Log.w(TAG, "Could not get user list", re);
return null;
@@ -488,7 +486,14 @@
*/
public List<UserHandle> getUserProfiles() {
ArrayList<UserHandle> profiles = new ArrayList<UserHandle>();
- List<UserInfo> users = getProfiles(UserHandle.myUserId());
+ List<UserInfo> users = new ArrayList<UserInfo>();
+ try {
+ // TODO: Switch enabledOnly to true once client apps are updated
+ users = mService.getProfiles(UserHandle.myUserId(), false /* enabledOnly */);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not get user list", re);
+ return null;
+ }
for (UserInfo info : users) {
UserHandle userHandle = new UserHandle(info.id);
profiles.add(userHandle);
@@ -552,7 +557,7 @@
/**
* Returns information for all users on this device. Requires
* {@link android.Manifest.permission#MANAGE_USERS} permission.
- *
+ *
* @param excludeDying specify if the list should exclude users being
* removed.
* @return the list of users that were created.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 9a768e0..b907375 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -17,7 +17,7 @@
package android.provider;
import static android.net.TrafficStats.KB_IN_BYTES;
-import static libcore.io.OsConstants.SEEK_SET;
+import static android.system.OsConstants.SEEK_SET;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -38,11 +38,11 @@
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.BufferedInputStream;
import java.io.File;
@@ -809,7 +809,7 @@
// optimal decode path; otherwise fall back to buffering.
BufferedInputStream is = null;
try {
- Libcore.os.lseek(fd, offset, SEEK_SET);
+ Os.lseek(fd, offset, SEEK_SET);
} catch (ErrnoException e) {
is = new BufferedInputStream(new FileInputStream(fd), THUMBNAIL_BUFFER_SIZE);
is.mark(THUMBNAIL_BUFFER_SIZE);
@@ -835,7 +835,7 @@
bitmap = BitmapFactory.decodeStream(is, null, opts);
} else {
try {
- Libcore.os.lseek(fd, offset, SEEK_SET);
+ Os.lseek(fd, offset, SEEK_SET);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7f9f862..ab06230 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -723,6 +723,13 @@
= "android.settings.NOTIFICATION_LISTENER_SETTINGS";
/**
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CONDITION_PROVIDER_SETTINGS
+ = "android.settings.ACTION_CONDITION_PROVIDER_SETTINGS";
+
+ /**
* Activity Action: Show settings for video captioning.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard
@@ -757,6 +764,11 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_ZEN_MODE_SETTINGS = "android.settings.ZEN_MODE_SETTINGS";
+ /** {@hide} */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String
+ ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
+
// End of Intent actions for Settings
/**
@@ -3311,6 +3323,12 @@
"input_method_selector_visibility";
/**
+ * The currently selected voice interaction service flattened ComponentName.
+ * @hide
+ */
+ public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
+
+ /**
* bluetooth HCI snoop log configuration
* @hide
*/
@@ -4510,6 +4528,11 @@
*/
public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
+ /**
+ * @hide
+ */
+ public static final String ENABLED_CONDITION_PROVIDERS = "enabled_condition_providers";
+
/** @hide */
public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
diff --git a/core/java/android/service/notification/Condition.aidl b/core/java/android/service/notification/Condition.aidl
new file mode 100644
index 0000000..432852c
--- /dev/null
+++ b/core/java/android/service/notification/Condition.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.notification;
+
+parcelable Condition;
+
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
new file mode 100644
index 0000000..71e3166
--- /dev/null
+++ b/core/java/android/service/notification/Condition.java
@@ -0,0 +1,147 @@
+/**
+ * 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.notification;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Condition information from condition providers.
+ *
+ * @hide
+ */
+public class Condition implements Parcelable {
+
+ public static final String SCHEME = "condition";
+
+ public static final int STATE_FALSE = 0;
+ public static final int STATE_TRUE = 1;
+ public static final int STATE_UNKNOWN = 2;
+ public static final int STATE_ERROR = 3;
+
+ public static final int FLAG_RELEVANT_NOW = 1 << 0;
+ public static final int FLAG_RELEVANT_ALWAYS = 1 << 1;
+
+ public final Uri id;
+ public String caption;
+ public int state;
+ public int flags;
+
+ public Condition(Uri id, String caption, int state, int flags) {
+ if (id == null) throw new IllegalArgumentException("id is required");
+ if (caption == null) throw new IllegalArgumentException("caption is required");
+ if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
+ this.id = id;
+ this.caption = caption;
+ this.state = state;
+ this.flags = flags;
+ }
+
+ private Condition(Parcel source) {
+ this((Uri)source.readParcelable(Condition.class.getClassLoader()),
+ source.readString(),
+ source.readInt(),
+ source.readInt());
+ }
+
+ private static boolean isValidState(int state) {
+ return state >= STATE_FALSE && state <= STATE_ERROR;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(id, 0);
+ dest.writeString(caption);
+ dest.writeInt(state);
+ dest.writeInt(flags);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(Condition.class.getSimpleName()).append('[')
+ .append("id=").append(id)
+ .append(",caption=").append(caption)
+ .append(",state=").append(stateToString(state))
+ .append(",flags=").append(flags)
+ .append(']').toString();
+ }
+
+ public static String stateToString(int state) {
+ if (state == STATE_FALSE) return "STATE_FALSE";
+ if (state == STATE_TRUE) return "STATE_TRUE";
+ if (state == STATE_UNKNOWN) return "STATE_UNKNOWN";
+ if (state == STATE_ERROR) return "STATE_ERROR";
+ throw new IllegalArgumentException("state is invalid: " + state);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Condition)) return false;
+ if (o == this) return true;
+ final Condition other = (Condition) o;
+ return Objects.equals(other.id, id)
+ && Objects.equals(other.caption, caption)
+ && other.state == state
+ && other.flags == flags;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, caption, state, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public Condition copy() {
+ final Parcel parcel = Parcel.obtain();
+ try {
+ writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return new Condition(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ public static Uri.Builder newId(Context context) {
+ return new Uri.Builder().scheme(SCHEME).authority(context.getPackageName());
+ }
+
+ public static boolean isValidId(Uri id, String pkg) {
+ return id != null && id.getScheme().equals(SCHEME) && id.getAuthority().equals(pkg);
+ }
+
+ public static final Parcelable.Creator<Condition> CREATOR
+ = new Parcelable.Creator<Condition>() {
+ @Override
+ public Condition createFromParcel(Parcel source) {
+ return new Condition(source);
+ }
+
+ @Override
+ public Condition[] newArray(int size) {
+ return new Condition[size];
+ }
+ };
+}
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
new file mode 100644
index 0000000..d6ef8f5
--- /dev/null
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -0,0 +1,141 @@
+/*
+ * 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.notification;
+
+import android.annotation.SdkConstant;
+import android.app.INotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * A service that provides conditions about boolean state.
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_CONDITION_PROVIDER_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * <service android:name=".MyConditionProvider"
+ * android:label="@string/service_name"
+ * android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.service.notification.ConditionProviderService" />
+ * </intent-filter>
+ * </service></pre>
+ *
+ * @hide
+ */
+public abstract class ConditionProviderService extends Service {
+ private final String TAG = ConditionProviderService.class.getSimpleName()
+ + "[" + getClass().getSimpleName() + "]";
+
+ private Provider mProvider;
+ private INotificationManager mNoMan;
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE
+ = "android.service.notification.ConditionProviderService";
+
+ abstract public void onConnected();
+ abstract public void onRequestConditions(int relevance);
+ abstract public void onSubscribe(Uri conditionId);
+ abstract public void onUnsubscribe(Uri conditionId);
+
+ private final INotificationManager getNotificationInterface() {
+ if (mNoMan == null) {
+ mNoMan = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ }
+ return mNoMan;
+ }
+
+ public final void notifyCondition(Condition condition) {
+ if (condition == null) return;
+ notifyConditions(new Condition[]{ condition });
+ }
+
+ public final void notifyConditions(Condition... conditions) {
+ if (!isBound() || conditions == null) return;
+ try {
+ getNotificationInterface().notifyConditions(getPackageName(), mProvider, conditions);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (mProvider == null) {
+ mProvider = new Provider();
+ }
+ return mProvider;
+ }
+
+ private boolean isBound() {
+ if (mProvider == null) {
+ Log.w(TAG, "Condition provider service not yet bound.");
+ return false;
+ }
+ return true;
+ }
+
+ private final class Provider extends IConditionProvider.Stub {
+ private final ConditionProviderService mService = ConditionProviderService.this;
+
+ @Override
+ public void onConnected() {
+ try {
+ mService.onConnected();
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onConnected", t);
+ }
+ }
+
+ @Override
+ public void onRequestConditions(int relevance) {
+ try {
+ mService.onRequestConditions(relevance);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onRequestConditions", t);
+ }
+ }
+
+ @Override
+ public void onSubscribe(Uri conditionId) {
+ try {
+ mService.onSubscribe(conditionId);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onSubscribe", t);
+ }
+ }
+
+ @Override
+ public void onUnsubscribe(Uri conditionId) {
+ try {
+ mService.onUnsubscribe(conditionId);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onUnsubscribe", t);
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/notification/IConditionListener.aidl b/core/java/android/service/notification/IConditionListener.aidl
new file mode 100644
index 0000000..01f874f
--- /dev/null
+++ b/core/java/android/service/notification/IConditionListener.aidl
@@ -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.
+ */
+
+package android.service.notification;
+
+import android.net.Uri;
+import android.service.notification.Condition;
+
+/** @hide */
+oneway interface IConditionListener {
+ void onConditionsReceived(in Condition[] conditions);
+}
\ No newline at end of file
diff --git a/core/java/android/service/notification/IConditionProvider.aidl b/core/java/android/service/notification/IConditionProvider.aidl
new file mode 100644
index 0000000..ada8939
--- /dev/null
+++ b/core/java/android/service/notification/IConditionProvider.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import android.net.Uri;
+import android.service.notification.Condition;
+
+/** @hide */
+oneway interface IConditionProvider {
+ void onConnected();
+ void onRequestConditions(int relevance);
+ void onSubscribe(in Uri conditionId);
+ void onUnsubscribe(in Uri conditionId);
+}
\ No newline at end of file
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 2c0b76d..72720d1 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -87,7 +87,7 @@
}
private String key() {
- return pkg + '|' + opPkg + '|' + id + '|' + tag + '|' + uid;
+ return pkg + '|' + id + '|' + tag + '|' + uid;
}
public void writeToParcel(Parcel out, int flags) {
diff --git a/core/java/android/service/voice/IVoiceInteractionService.aidl b/core/java/android/service/voice/IVoiceInteractionService.aidl
new file mode 100644
index 0000000..e9e2f4c
--- /dev/null
+++ b/core/java/android/service/voice/IVoiceInteractionService.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.voice;
+
+/**
+ * @hide
+ */
+oneway interface IVoiceInteractionService {
+}
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
new file mode 100644
index 0000000..7dbf66b
--- /dev/null
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.voice;
+
+import android.os.Bundle;
+
+import com.android.internal.app.IVoiceInteractorCallback;
+import com.android.internal.app.IVoiceInteractorRequest;
+
+/**
+ * @hide
+ */
+interface IVoiceInteractionSession {
+}
diff --git a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl
new file mode 100644
index 0000000..2519442
--- /dev/null
+++ b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.voice;
+
+import android.os.Bundle;
+
+import android.service.voice.IVoiceInteractionSession;
+
+/**
+ * @hide
+ */
+oneway interface IVoiceInteractionSessionService {
+ void newSession(IBinder token, in Bundle args);
+}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
new file mode 100644
index 0000000..d005890
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -0,0 +1,77 @@
+/**
+ * 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.voice;
+
+import android.annotation.SdkConstant;
+import android.app.Instrumentation;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import com.android.internal.app.IVoiceInteractionManagerService;
+
+public class VoiceInteractionService extends Service {
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ * To be supported, the service must also require the
+ * {@link android.Manifest.permission#BIND_VOICE_INTERACTION} permission so
+ * that other applications can not abuse it.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "android.service.voice.VoiceInteractionService";
+
+ /**
+ * Name under which a VoiceInteractionService component publishes information about itself.
+ * This meta-data should reference an XML resource containing a
+ * <code><{@link
+ * android.R.styleable#VoiceInteractionService voice-interaction-service}></code> tag.
+ */
+ public static final String SERVICE_META_DATA = "android.voice_interaction";
+
+ IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
+ };
+
+ IVoiceInteractionManagerService mSystemService;
+
+ public void startVoiceActivity(Intent intent, Bundle sessionArgs) {
+ try {
+ mSystemService.startVoiceActivity(intent,
+ intent.resolveType(getContentResolver()),
+ mInterface, sessionArgs);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
+ ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mInterface.asBinder();
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
new file mode 100644
index 0000000..a909ead
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
@@ -0,0 +1,125 @@
+/*
+ * 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.voice;
+
+import android.Manifest;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.speech.RecognitionService;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** @hide */
+public class VoiceInteractionServiceInfo {
+ static final String TAG = "VoiceInteractionServiceInfo";
+
+ private String mParseError;
+
+ private ServiceInfo mServiceInfo;
+ private String mSessionService;
+ private String mSettingsActivity;
+
+ public VoiceInteractionServiceInfo(PackageManager pm, ComponentName comp)
+ throws PackageManager.NameNotFoundException {
+ this(pm, pm.getServiceInfo(comp, PackageManager.GET_META_DATA));
+ }
+
+ public VoiceInteractionServiceInfo(PackageManager pm, ServiceInfo si) {
+ if (!Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) {
+ mParseError = "Service does not require permission "
+ + Manifest.permission.BIND_VOICE_INTERACTION;
+ return;
+ }
+
+ XmlResourceParser parser = null;
+ try {
+ parser = si.loadXmlMetaData(pm, VoiceInteractionService.SERVICE_META_DATA);
+ if (parser == null) {
+ mParseError = "No " + VoiceInteractionService.SERVICE_META_DATA
+ + " meta-data for " + si.packageName;
+ return;
+ }
+
+ Resources res = pm.getResourcesForApplication(si.applicationInfo);
+
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+
+ String nodeName = parser.getName();
+ if (!"voice-interaction-service".equals(nodeName)) {
+ mParseError = "Meta-data does not start with voice-interaction-service tag";
+ return;
+ }
+
+ TypedArray array = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.VoiceInteractionService);
+ mSessionService = array.getString(
+ com.android.internal.R.styleable.VoiceInteractionService_sessionService);
+ mSettingsActivity = array.getString(
+ com.android.internal.R.styleable.VoiceInteractionService_settingsActivity);
+ array.recycle();
+ if (mSessionService == null) {
+ mParseError = "No sessionService specified";
+ return;
+ }
+ } catch (XmlPullParserException e) {
+ mParseError = "Error parsing voice interation service meta-data: " + e;
+ Log.w(TAG, "error parsing voice interaction service meta-data", e);
+ return;
+ } catch (IOException e) {
+ mParseError = "Error parsing voice interation service meta-data: " + e;
+ Log.w(TAG, "error parsing voice interaction service meta-data", e);
+ return;
+ } catch (PackageManager.NameNotFoundException e) {
+ mParseError = "Error parsing voice interation service meta-data: " + e;
+ Log.w(TAG, "error parsing voice interaction service meta-data", e);
+ return;
+ } finally {
+ if (parser != null) parser.close();
+ }
+ mServiceInfo = si;
+ }
+
+ public String getParseError() {
+ return mParseError;
+ }
+
+ public ServiceInfo getServiceInfo() {
+ return mServiceInfo;
+ }
+
+ public String getSessionService() {
+ return mSessionService;
+ }
+
+ public String getSettingsActivity() {
+ return mSettingsActivity;
+ }
+}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
new file mode 100644
index 0000000..963b6b4
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -0,0 +1,195 @@
+/**
+ * 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.voice;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.IVoiceInteractorCallback;
+import com.android.internal.app.IVoiceInteractorRequest;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+
+public abstract class VoiceInteractionSession {
+ static final String TAG = "VoiceInteractionSession";
+ static final boolean DEBUG = true;
+
+ final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
+ @Override
+ public IVoiceInteractorRequest startConfirmation(String callingPackage,
+ IVoiceInteractorCallback callback, String prompt, Bundle extras) {
+ Request request = findRequest(callback, true);
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_CONFIRMATION,
+ new Caller(callingPackage, Binder.getCallingUid()), request,
+ prompt, extras));
+ return request.mInterface;
+ }
+
+ @Override
+ public IVoiceInteractorRequest startCommand(String callingPackage,
+ IVoiceInteractorCallback callback, String command, Bundle extras) {
+ Request request = findRequest(callback, true);
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMMAND,
+ new Caller(callingPackage, Binder.getCallingUid()), request,
+ command, extras));
+ return request.mInterface;
+ }
+
+ @Override
+ public boolean[] supportsCommands(String callingPackage, String[] commands) {
+ Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS,
+ 0, new Caller(callingPackage, Binder.getCallingUid()), commands);
+ SomeArgs args = mHandlerCaller.sendMessageAndWait(msg);
+ if (args != null) {
+ boolean[] res = (boolean[])args.arg1;
+ args.recycle();
+ return res;
+ }
+ return new boolean[commands.length];
+ }
+ };
+
+ final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
+ };
+
+ public static class Request {
+ final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() {
+ @Override
+ public void cancel() throws RemoteException {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_CANCEL, Request.this));
+ }
+ };
+ final IVoiceInteractorCallback mCallback;
+ final HandlerCaller mHandlerCaller;
+ Request(IVoiceInteractorCallback callback, HandlerCaller handlerCaller) {
+ mCallback = callback;
+ mHandlerCaller = handlerCaller;
+ }
+
+ public void sendConfirmResult(boolean confirmed, Bundle result) {
+ try {
+ if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface
+ + " confirmed=" + confirmed + " result=" + result);
+ mCallback.deliverConfirmationResult(mInterface, confirmed, result);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void sendCommandResult(boolean complete, Bundle result) {
+ try {
+ if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface
+ + " result=" + result);
+ mCallback.deliverCommandResult(mInterface, complete, result);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void sendCancelResult() {
+ try {
+ if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface);
+ mCallback.deliverCancel(mInterface);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ public static class Caller {
+ final String packageName;
+ final int uid;
+
+ Caller(String _packageName, int _uid) {
+ packageName = _packageName;
+ uid = _uid;
+ }
+ }
+
+ static final int MSG_START_CONFIRMATION = 1;
+ static final int MSG_START_COMMAND = 2;
+ static final int MSG_SUPPORTS_COMMANDS = 3;
+ static final int MSG_CANCEL = 4;
+
+ final Context mContext;
+ final HandlerCaller mHandlerCaller;
+ final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() {
+ @Override
+ public void executeMessage(Message msg) {
+ SomeArgs args = (SomeArgs)msg.obj;
+ switch (msg.what) {
+ case MSG_START_CONFIRMATION:
+ if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface
+ + " prompt=" + args.arg3 + " extras=" + args.arg4);
+ onConfirm((Caller)args.arg1, (Request)args.arg2, (String)args.arg3,
+ (Bundle)args.arg4);
+ break;
+ case MSG_START_COMMAND:
+ if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface
+ + " command=" + args.arg3 + " extras=" + args.arg4);
+ onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3,
+ (Bundle) args.arg4);
+ break;
+ case MSG_SUPPORTS_COMMANDS:
+ if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2);
+ args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
+ break;
+ case MSG_CANCEL:
+ if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
+ onCancel((Request)args.arg1);
+ break;
+ }
+ }
+ };
+
+ final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+
+ public VoiceInteractionSession(Context context) {
+ this(context, new Handler());
+ }
+
+ public VoiceInteractionSession(Context context, Handler handler) {
+ mContext = context;
+ mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
+ mHandlerCallerCallback, true);
+ }
+
+ Request findRequest(IVoiceInteractorCallback callback, boolean newRequest) {
+ synchronized (this) {
+ Request req = mActiveRequests.get(callback.asBinder());
+ if (req != null) {
+ if (newRequest) {
+ throw new IllegalArgumentException("Given request callback " + callback
+ + " is already active");
+ }
+ return req;
+ }
+ req = new Request(callback, mHandlerCaller);
+ mActiveRequests.put(callback.asBinder(), req);
+ return req;
+ }
+ }
+
+ public abstract boolean[] onGetSupportedCommands(Caller caller, String[] commands);
+ public abstract void onConfirm(Caller caller, Request request, String prompt, Bundle extras);
+ public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
+ public abstract void onCancel(Request request);
+}
diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java
new file mode 100644
index 0000000..40e5bba
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionSessionService.java
@@ -0,0 +1,82 @@
+/**
+ * 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.voice;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+
+public abstract class VoiceInteractionSessionService extends Service {
+
+ static final int MSG_NEW_SESSION = 1;
+
+ IVoiceInteractionManagerService mSystemService;
+
+ IVoiceInteractionSessionService mInterface = new IVoiceInteractionSessionService.Stub() {
+ public void newSession(IBinder token, Bundle args) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(MSG_NEW_SESSION,
+ token, args));
+
+ }
+ };
+
+ HandlerCaller mHandlerCaller;
+ final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() {
+ @Override
+ public void executeMessage(Message msg) {
+ SomeArgs args = (SomeArgs)msg.obj;
+ switch (msg.what) {
+ case MSG_NEW_SESSION:
+ doNewSession((IBinder)args.arg1, (Bundle)args.arg2);
+ break;
+ }
+ }
+ };
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
+ ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
+ mHandlerCaller = new HandlerCaller(this, Looper.myLooper(),
+ mHandlerCallerCallback, true);
+ }
+
+ public abstract VoiceInteractionSession onNewSession(Bundle args);
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mInterface.asBinder();
+ }
+
+ void doNewSession(IBinder token, Bundle args) {
+ VoiceInteractionSession session = onNewSession(args);
+ try {
+ mSystemService.deliverNewSession(token, session.mSession, session.mInteractor);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 77cd71e..6f00707 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -188,10 +188,6 @@
spacing = metrics.descent - metrics.ascent;
}
- if (spacingmult != 1 || spacingadd != 0) {
- spacing = (int)(spacing * spacingmult + spacingadd + 0.5f);
- }
-
mBottom = spacing;
if (includepad) {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 638ef22..0db00f0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -632,7 +632,11 @@
bottom = fm.bottom;
}
- if (j == 0) {
+ boolean firstLine = (j == 0);
+ boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
+ boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd);
+
+ if (firstLine) {
if (trackPad) {
mTopPadding = top - above;
}
@@ -641,7 +645,10 @@
above = top;
}
}
- if (end == bufEnd) {
+
+ int extra;
+
+ if (lastLine) {
if (trackPad) {
mBottomPadding = bottom - below;
}
@@ -651,9 +658,8 @@
}
}
- int extra;
- if (needMultiply) {
+ if (needMultiply && !lastLine) {
double ex = (below - above) * (spacingmult - 1) + spacingadd;
if (ex >= 0) {
extra = (int)(ex + EXTRA_ROUNDING);
@@ -690,8 +696,6 @@
if (ellipsize != null) {
// If there is only one line, then do any type of ellipsis except when it is MARQUEE
// if there are multiple lines, just allow END ellipsis on the last line
- boolean firstLine = (j == 0);
- boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount);
boolean doEllipsis =
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 08e27d3..e70dc0c 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -105,7 +105,7 @@
if (DBG) {
Log.d(LOG_TAG, "Created animator " + anim);
}
- FadeAnimatorListener listener = new FadeAnimatorListener(view, endAlpha);
+ FadeAnimatorListener listener = new FadeAnimatorListener(view);
anim.addListener(listener);
anim.addPauseListener(listener);
return anim;
@@ -138,13 +138,11 @@
private static class FadeAnimatorListener extends AnimatorListenerAdapter {
private final View mView;
- private final float mEndAlpha;
private boolean mCanceled = false;
- private float mPausedAlpha;
+ private float mPausedAlpha = -1;
- public FadeAnimatorListener(View view, float endAlpha) {
+ public FadeAnimatorListener(View view) {
mView = view;
- mEndAlpha = endAlpha;
}
@Override
@@ -158,14 +156,14 @@
@Override
public void onAnimationEnd(Animator animator) {
if (!mCanceled) {
- mView.setTransitionAlpha(mEndAlpha);
+ mView.setTransitionAlpha(1);
}
}
@Override
public void onAnimationPause(Animator animator) {
mPausedAlpha = mView.getTransitionAlpha();
- mView.setTransitionAlpha(mEndAlpha);
+ mView.setTransitionAlpha(1);
}
@Override
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 966b24d..9081234 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -256,11 +256,45 @@
@Override
protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
TransitionValuesMaps endValues) {
+ startValues = removeExcludes(startValues);
+ endValues = removeExcludes(endValues);
for (Transition childTransition : mTransitions) {
childTransition.createAnimators(sceneRoot, startValues, endValues);
}
}
+ private TransitionValuesMaps removeExcludes(TransitionValuesMaps values) {
+ if (mTargetIds.isEmpty() && mTargetIdExcludes == null && mTargetTypeExcludes == null
+ && mTargets.isEmpty()) {
+ return values;
+ }
+ TransitionValuesMaps included = new TransitionValuesMaps();
+ int numValues = values.viewValues.size();
+ for (int i = 0; i < numValues; i++) {
+ View view = values.viewValues.keyAt(i);
+ if (isValidTarget(view, view.getId())) {
+ included.viewValues.put(view, values.viewValues.valueAt(i));
+ }
+ }
+ numValues = values.idValues.size();
+ for (int i = 0; i < numValues; i++) {
+ int id = values.idValues.keyAt(i);
+ TransitionValues transitionValues = values.idValues.valueAt(i);
+ if (isValidTarget(transitionValues.view, id)) {
+ included.idValues.put(id, transitionValues);
+ }
+ }
+ numValues = values.itemIdValues.size();
+ for (int i = 0; i < numValues; i++) {
+ long id = values.itemIdValues.keyAt(i);
+ TransitionValues transitionValues = values.itemIdValues.valueAt(i);
+ if (isValidTarget(transitionValues.view, id)) {
+ included.itemIdValues.put(id, transitionValues);
+ }
+ }
+ return included;
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 526803a..6e6496c 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -347,10 +347,11 @@
}
if (viewToKeep != null) {
+ int originalVisibility = viewToKeep.getVisibility();
viewToKeep.setVisibility(View.VISIBLE);
Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues);
if (animator == null) {
- viewToKeep.setVisibility(finalVisibility);
+ viewToKeep.setVisibility(originalVisibility);
} else {
final View finalViewToKeep = viewToKeep;
animator.addListener(new AnimatorListenerAdapter() {
diff --git a/core/java/android/tv/ITvInputClient.aidl b/core/java/android/tv/ITvInputClient.aidl
index 43be6f0..538f8a1 100644
--- a/core/java/android/tv/ITvInputClient.aidl
+++ b/core/java/android/tv/ITvInputClient.aidl
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.tv.ITvInputSession;
+import android.view.InputChannel;
/**
* Interface a client of the ITvInputManager implements, to identify itself and receive information
@@ -25,6 +26,6 @@
* @hide
*/
oneway interface ITvInputClient {
- void onSessionCreated(in ComponentName name, IBinder token, int seq);
+ void onSessionCreated(in ComponentName name, IBinder token, in InputChannel channel, int seq);
void onAvailabilityChanged(in ComponentName name, boolean isAvailable);
}
diff --git a/core/java/android/tv/ITvInputService.aidl b/core/java/android/tv/ITvInputService.aidl
index 672784f..4f1bc2b 100644
--- a/core/java/android/tv/ITvInputService.aidl
+++ b/core/java/android/tv/ITvInputService.aidl
@@ -18,6 +18,7 @@
import android.tv.ITvInputServiceCallback;
import android.tv.ITvInputSessionCallback;
+import android.view.InputChannel;
/**
* Top-level interface to a TV input component (implemented in a Service).
@@ -26,5 +27,5 @@
oneway interface ITvInputService {
void registerCallback(ITvInputServiceCallback callback);
void unregisterCallback(in ITvInputServiceCallback callback);
- void createSession(ITvInputSessionCallback callback);
+ void createSession(in InputChannel channel, ITvInputSessionCallback callback);
}
diff --git a/core/java/android/tv/ITvInputSessionWrapper.java b/core/java/android/tv/ITvInputSessionWrapper.java
index a6e0877..3ccccf3 100644
--- a/core/java/android/tv/ITvInputSessionWrapper.java
+++ b/core/java/android/tv/ITvInputSessionWrapper.java
@@ -20,9 +20,16 @@
import android.graphics.Rect;
import android.net.Uri;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
+import android.tv.TvInputManager.Session;
import android.tv.TvInputService.TvInputSessionImpl;
import android.util.Log;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.Surface;
import com.android.internal.os.HandlerCaller;
@@ -45,50 +52,66 @@
private static final int DO_RELAYOUT_OVERLAY_VIEW = 6;
private static final int DO_REMOVE_OVERLAY_VIEW = 7;
- private TvInputSessionImpl mTvInputSession;
private final HandlerCaller mCaller;
- public ITvInputSessionWrapper(Context context, TvInputSessionImpl session) {
+ private TvInputSessionImpl mTvInputSessionImpl;
+ private InputChannel mChannel;
+ private TvInputEventReceiver mReceiver;
+
+ public ITvInputSessionWrapper(Context context, TvInputSessionImpl sessionImpl,
+ InputChannel channel) {
mCaller = new HandlerCaller(context, null, this, true /* asyncHandler */);
- mTvInputSession = session;
+ mTvInputSessionImpl = sessionImpl;
+ mChannel = channel;
+ if (channel != null) {
+ mReceiver = new TvInputEventReceiver(channel, context.getMainLooper());
+ }
}
@Override
public void executeMessage(Message msg) {
- if (mTvInputSession == null) {
+ if (mTvInputSessionImpl == null) {
return;
}
switch (msg.what) {
case DO_RELEASE: {
- mTvInputSession.release();
- mTvInputSession = null;
+ mTvInputSessionImpl.release();
+ mTvInputSessionImpl = null;
+ if (mReceiver != null) {
+ mReceiver.dispose();
+ mReceiver = null;
+ }
+ if (mChannel != null) {
+ mChannel.dispose();
+ mChannel = null;
+ }
return;
}
case DO_SET_SURFACE: {
- mTvInputSession.setSurface((Surface) msg.obj);
+ mTvInputSessionImpl.setSurface((Surface) msg.obj);
return;
}
case DO_SET_VOLUME: {
- mTvInputSession.setVolume((Float) msg.obj);
+ mTvInputSessionImpl.setVolume((Float) msg.obj);
return;
}
case DO_TUNE: {
- mTvInputSession.tune((Uri) msg.obj);
+ mTvInputSessionImpl.tune((Uri) msg.obj);
return;
}
case DO_CREATE_OVERLAY_VIEW: {
SomeArgs args = (SomeArgs) msg.obj;
- mTvInputSession.createOverlayView((IBinder) args.arg1, (Rect) args.arg2);
+ mTvInputSessionImpl.createOverlayView((IBinder) args.arg1, (Rect) args.arg2);
args.recycle();
return;
}
case DO_RELAYOUT_OVERLAY_VIEW: {
- mTvInputSession.relayoutOverlayView((Rect) msg.obj);
+ mTvInputSessionImpl.relayoutOverlayView((Rect) msg.obj);
return;
}
case DO_REMOVE_OVERLAY_VIEW: {
- mTvInputSession.removeOverlayView(true);
+ mTvInputSessionImpl.removeOverlayView(true);
return;
}
default: {
@@ -133,4 +156,24 @@
public void removeOverlayView() {
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_OVERLAY_VIEW));
}
+
+ private final class TvInputEventReceiver extends InputEventReceiver {
+ public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ if (mTvInputSessionImpl == null) {
+ // The session has been finished.
+ finishInputEvent(event, false);
+ return;
+ }
+
+ int handled = mTvInputSessionImpl.dispatchInputEvent(event, this);
+ if (handled != Session.DISPATCH_IN_PROGRESS) {
+ finishInputEvent(event, handled == Session.DISPATCH_HANDLED);
+ }
+ }
+ }
}
diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java
index 05f0b9c..7b9b1fb 100644
--- a/core/java/android/tv/TvInputManager.java
+++ b/core/java/android/tv/TvInputManager.java
@@ -21,9 +21,16 @@
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Pools.Pool;
+import android.util.Pools.SimplePool;
import android.util.SparseArray;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventSender;
import android.view.Surface;
import android.view.View;
@@ -138,7 +145,8 @@
mUserId = userId;
mClient = new ITvInputClient.Stub() {
@Override
- public void onSessionCreated(ComponentName name, IBinder token, int seq) {
+ public void onSessionCreated(ComponentName name, IBinder token, InputChannel channel,
+ int seq) {
synchronized (mSessionCreateCallbackRecordMap) {
SessionCreateCallbackRecord record = mSessionCreateCallbackRecordMap.get(seq);
mSessionCreateCallbackRecordMap.delete(seq);
@@ -148,7 +156,7 @@
}
Session session = null;
if (token != null) {
- session = new Session(name, token, mService, mUserId);
+ session = new Session(token, channel, mService, mUserId);
}
record.postSessionCreated(session);
}
@@ -321,13 +329,30 @@
/** The Session provides the per-session functionality of TV inputs. */
public static final class Session {
+ static final int DISPATCH_IN_PROGRESS = -1;
+ static final int DISPATCH_NOT_HANDLED = 0;
+ static final int DISPATCH_HANDLED = 1;
+
+ private static final long INPUT_SESSION_NOT_RESPONDING_TIMEOUT = 2500;
+
private final ITvInputManager mService;
private final int mUserId;
+
+ // For scheduling input event handling on the main thread. This also serves as a lock to
+ // protect pending input events and the input channel.
+ private final InputEventHandler mHandler = new InputEventHandler(Looper.getMainLooper());
+
+ private final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20);
+ private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20);
+
private IBinder mToken;
+ private TvInputEventSender mSender;
+ private InputChannel mChannel;
/** @hide */
- private Session(ComponentName name, IBinder token, ITvInputManager service, int userId) {
+ private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId) {
mToken = token;
+ mChannel = channel;
mService = service;
mUserId = userId;
}
@@ -347,6 +372,18 @@
} catch (RemoteException e) {
throw new RuntimeException(e);
}
+
+ synchronized (mHandler) {
+ if (mChannel != null) {
+ if (mSender != null) {
+ flushPendingEventsLocked();
+ mSender.dispose();
+ mSender = null;
+ }
+ mChannel.dispose();
+ mChannel = null;
+ }
+ }
}
/**
@@ -478,5 +515,228 @@
throw new RuntimeException(e);
}
}
+
+ /**
+ * Dispatches an input event to this session.
+ *
+ * @param event {@link InputEvent} to dispatch.
+ * @param token A token used to identify the input event later in the callback.
+ * @param callback A callback used to receive the dispatch result.
+ * @param handler {@link Handler} that the dispatch result will be delivered to.
+ * @return Returns {@link #DISPATCH_HANDLED} if the event was handled. Returns
+ * {@link #DISPATCH_NOT_HANDLED} if the event was not handled. Returns
+ * {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the callback will
+ * be invoked later.
+ * @throws IllegalArgumentException if any of the necessary arguments is {@code null}.
+ * @hide
+ */
+ public int dispatchInputEvent(InputEvent event, Object token,
+ FinishedInputEventCallback callback, Handler handler) {
+ if (event == null) {
+ throw new IllegalArgumentException("event cannot be null");
+ }
+ if (callback != null && handler == null) {
+ throw new IllegalArgumentException("handler cannot be null");
+ }
+ synchronized (mHandler) {
+ if (mChannel == null) {
+ return DISPATCH_NOT_HANDLED;
+ }
+ PendingEvent p = obtainPendingEventLocked(event, token, callback, handler);
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ // Already running on the main thread so we can send the event immediately.
+ return sendInputEventOnMainLooperLocked(p);
+ }
+
+ // Post the event to the main thread.
+ Message msg = mHandler.obtainMessage(InputEventHandler.MSG_SEND_INPUT_EVENT, p);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ return DISPATCH_IN_PROGRESS;
+ }
+ }
+
+ /**
+ * Callback that is invoked when an input event that was dispatched to this session has been
+ * finished.
+ *
+ * @hide
+ */
+ public interface FinishedInputEventCallback {
+ /**
+ * Called when the dispatched input event is finished.
+ *
+ * @param token a token passed to {@link #dispatchInputEvent}.
+ * @param handled {@code true} if the dispatched input event was handled properly.
+ * {@code false} otherwise.
+ */
+ public void onFinishedInputEvent(Object token, boolean handled);
+ }
+
+ // Must be called on the main looper
+ private void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
+ synchronized (mHandler) {
+ int result = sendInputEventOnMainLooperLocked(p);
+ if (result == DISPATCH_IN_PROGRESS) {
+ return;
+ }
+ }
+
+ invokeFinishedInputEventCallback(p, false);
+ }
+
+ private int sendInputEventOnMainLooperLocked(PendingEvent p) {
+ if (mChannel != null) {
+ if (mSender == null) {
+ mSender = new TvInputEventSender(mChannel, mHandler.getLooper());
+ }
+
+ final InputEvent event = p.mEvent;
+ final int seq = event.getSequenceNumber();
+ if (mSender.sendInputEvent(seq, event)) {
+ mPendingEvents.put(seq, p);
+ Message msg = mHandler.obtainMessage(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg, INPUT_SESSION_NOT_RESPONDING_TIMEOUT);
+ return DISPATCH_IN_PROGRESS;
+ }
+
+ Log.w(TAG, "Unable to send input event to session: " + mToken + " dropping:"
+ + event);
+ }
+ return DISPATCH_NOT_HANDLED;
+ }
+
+ void finishedInputEvent(int seq, boolean handled, boolean timeout) {
+ final PendingEvent p;
+ synchronized (mHandler) {
+ int index = mPendingEvents.indexOfKey(seq);
+ if (index < 0) {
+ return; // spurious, event already finished or timed out
+ }
+
+ p = mPendingEvents.valueAt(index);
+ mPendingEvents.removeAt(index);
+
+ if (timeout) {
+ Log.w(TAG, "Timeout waiting for seesion to handle input event after "
+ + INPUT_SESSION_NOT_RESPONDING_TIMEOUT + " ms: " + mToken);
+ } else {
+ mHandler.removeMessages(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
+ }
+ }
+
+ invokeFinishedInputEventCallback(p, handled);
+ }
+
+ // Assumes the event has already been removed from the queue.
+ void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
+ p.mHandled = handled;
+ if (p.mHandler.getLooper().isCurrentThread()) {
+ // Already running on the callback handler thread so we can send the callback
+ // immediately.
+ p.run();
+ } else {
+ // Post the event to the callback handler thread.
+ // In this case, the callback will be responsible for recycling the event.
+ Message msg = Message.obtain(p.mHandler, p);
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
+ }
+ }
+
+ private void flushPendingEventsLocked() {
+ mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
+
+ final int count = mPendingEvents.size();
+ for (int i = 0; i < count; i++) {
+ int seq = mPendingEvents.keyAt(i);
+ Message msg = mHandler.obtainMessage(InputEventHandler.MSG_FLUSH_INPUT_EVENT, seq, 0);
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
+ }
+ }
+
+ private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
+ FinishedInputEventCallback callback, Handler handler) {
+ PendingEvent p = mPendingEventPool.acquire();
+ if (p == null) {
+ p = new PendingEvent();
+ }
+ p.mEvent = event;
+ p.mToken = token;
+ p.mCallback = callback;
+ p.mHandler = handler;
+ return p;
+ }
+
+ private void recyclePendingEventLocked(PendingEvent p) {
+ p.recycle();
+ mPendingEventPool.release(p);
+ }
+
+ private final class InputEventHandler extends Handler {
+ public static final int MSG_SEND_INPUT_EVENT = 1;
+ public static final int MSG_TIMEOUT_INPUT_EVENT = 2;
+ public static final int MSG_FLUSH_INPUT_EVENT = 3;
+
+ InputEventHandler(Looper looper) {
+ super(looper, null, true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SEND_INPUT_EVENT: {
+ sendInputEventAndReportResultOnMainLooper((PendingEvent) msg.obj);
+ return;
+ }
+ case MSG_TIMEOUT_INPUT_EVENT: {
+ finishedInputEvent(msg.arg1, false, true);
+ return;
+ }
+ case MSG_FLUSH_INPUT_EVENT: {
+ finishedInputEvent(msg.arg1, false, false);
+ return;
+ }
+ }
+ }
+ }
+
+ private final class TvInputEventSender extends InputEventSender {
+ public TvInputEventSender(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
+ @Override
+ public void onInputEventFinished(int seq, boolean handled) {
+ finishedInputEvent(seq, handled, false);
+ }
+ }
+
+ private final class PendingEvent implements Runnable {
+ public InputEvent mEvent;
+ public Object mToken;
+ public FinishedInputEventCallback mCallback;
+ public Handler mHandler;
+ public boolean mHandled;
+
+ public void recycle() {
+ mEvent = null;
+ mToken = null;
+ mCallback = null;
+ mHandler = null;
+ mHandled = false;
+ }
+
+ @Override
+ public void run() {
+ mCallback.onFinishedInputEvent(mToken, mHandled);
+
+ synchronized (mHandler) {
+ recyclePendingEventLocked(this);
+ }
+ }
+ }
}
}
diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java
index 80eb407..636e3b4 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/core/java/android/tv/TvInputService.java
@@ -28,13 +28,21 @@
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.tv.TvInputManager.Session;
import android.util.Log;
import android.view.Gravity;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
/**
* A base class for implementing television input service.
@@ -89,10 +97,17 @@
}
@Override
- public void createSession(ITvInputSessionCallback cb) {
- if (cb != null) {
- mHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, cb).sendToTarget();
+ public void createSession(InputChannel channel, ITvInputSessionCallback cb) {
+ if (channel == null) {
+ Log.w(TAG, "Creating session without input channel");
}
+ if (cb == null) {
+ return;
+ }
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = channel;
+ args.arg2 = cb;
+ mHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, args).sendToTarget();
}
};
}
@@ -131,7 +146,8 @@
/**
* Base class for derived classes to implement to provide {@link TvInputManager.Session}.
*/
- public abstract class TvInputSessionImpl {
+ public abstract class TvInputSessionImpl implements KeyEvent.Callback {
+ private final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
private final WindowManager mWindowManager;
private WindowManager.LayoutParams mWindowParams;
private View mOverlayView;
@@ -143,6 +159,13 @@
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
}
+ /**
+ * Enables or disables the overlay view. By default, the overlay view is disabled. Must be
+ * called explicitly after the session is created to enable the overlay view.
+ *
+ * @param enable {@code true} if you want to enable the overlay view. {@code false}
+ * otherwise.
+ */
public void setOverlayViewEnabled(final boolean enable) {
mHandler.post(new Runnable() {
@Override
@@ -203,6 +226,121 @@
}
/**
+ * Default implementation of {@link android.view.KeyEvent.Callback#onKeyDown(int, KeyEvent)
+ * KeyEvent.Callback.onKeyDown()}: always returns false (doesn't handle the event).
+ * <p>
+ * Override this to intercept key down events before they are processed by the application.
+ * If you return true, the application will not process the event itself. If you return
+ * false, the normal application processing will occur as if the TV input had not seen the
+ * event at all.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param event Description of the key event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Default implementation of
+ * {@link android.view.KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+ * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle the event).
+ * <p>
+ * Override this to intercept key long press events before they are processed by the
+ * application. If you return true, the application will not process the event itself. If
+ * you return false, the normal application processing will occur as if the TV input had not
+ * seen the event at all.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param event Description of the key event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Default implementation of
+ * {@link android.view.KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
+ * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle the event).
+ * <p>
+ * Override this to intercept special key multiple events before they are processed by the
+ * application. If you return true, the application will not itself process the event. If
+ * you return false, the normal application processing will occur as if the TV input had not
+ * seen the event at all.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param count The number of times the action was made.
+ * @param event Description of the key event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ @Override
+ public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Default implementation of {@link android.view.KeyEvent.Callback#onKeyUp(int, KeyEvent)
+ * KeyEvent.Callback.onKeyUp()}: always returns false (doesn't handle the event).
+ * <p>
+ * Override this to intercept key up events before they are processed by the application. If
+ * you return true, the application will not itself process the event. If you return false,
+ * the normal application processing will occur as if the TV input had not seen the event at
+ * all.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param event Description of the key event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Implement this method to handle touch screen motion events on the current input session.
+ *
+ * @param event The motion event being received.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ * @see View#onTouchEvent
+ */
+ public boolean onTouchEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
+ * Implement this method to handle trackball events on the current input session.
+ *
+ * @param event The motion event being received.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ * @see View#onTrackballEvent
+ */
+ public boolean onTrackballEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
+ * Implement this method to handle generic motion events on the current input session.
+ *
+ * @param event The motion event being received.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ * @see View#onGenericMotionEvent
+ */
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
* This method is called when the application would like to stop using the current input
* session.
*/
@@ -212,7 +350,7 @@
}
/**
- * Calls {@link onSetSurface}.
+ * Calls {@link #onSetSurface}.
*/
void setSurface(Surface surface) {
onSetSurface(surface);
@@ -220,14 +358,14 @@
}
/**
- * Calls {@link onSetVolume}.
+ * Calls {@link #onSetVolume}.
*/
void setVolume(float volume) {
onSetVolume(volume);
}
/**
- * Calls {@link onTune}.
+ * Calls {@link #onTune}.
*/
void tune(Uri channelUri) {
onTune(channelUri);
@@ -235,8 +373,8 @@
}
/**
- * Creates an overlay view. This calls {@link onCreateOverlayView} to get
- * a view to attach to the overlay window.
+ * Creates an overlay view. This calls {@link #onCreateOverlayView} to get a view to attach
+ * to the overlay window.
*
* @param windowToken A window token of an application.
* @param frame A position of the overlay view.
@@ -314,6 +452,42 @@
mWindowParams = null;
}
}
+
+ /**
+ * Takes care of dispatching incoming input events and tells whether the event was handled.
+ */
+ int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
+ if (DEBUG) Log.d(TAG, "dispatchInputEvent(" + event + ")");
+ if (event instanceof KeyEvent) {
+ if (((KeyEvent) event).dispatch(this, mDispatcherState, this)) {
+ return Session.DISPATCH_HANDLED;
+ }
+ } else if (event instanceof MotionEvent) {
+ MotionEvent motionEvent = (MotionEvent) event;
+ final int source = motionEvent.getSource();
+ if (motionEvent.isTouchEvent()) {
+ if (onTouchEvent(motionEvent)) {
+ return Session.DISPATCH_HANDLED;
+ }
+ } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
+ if (onTrackballEvent(motionEvent)) {
+ return Session.DISPATCH_HANDLED;
+ }
+ } else {
+ if (onGenericMotionEvent(motionEvent)) {
+ return Session.DISPATCH_HANDLED;
+ }
+ }
+ }
+ if (mOverlayView == null) {
+ return Session.DISPATCH_NOT_HANDLED;
+ }
+ if (!mOverlayView.hasWindowFocus()) {
+ mOverlayView.getViewRootImpl().windowFocusChanged(true, true);
+ }
+ mOverlayView.getViewRootImpl().dispatchInputEvent(event, receiver);
+ return Session.DISPATCH_IN_PROGRESS;
+ }
}
private final class ServiceHandler extends Handler {
@@ -324,20 +498,23 @@
public final void handleMessage(Message msg) {
switch (msg.what) {
case DO_CREATE_SESSION: {
- ITvInputSessionCallback cb = (ITvInputSessionCallback) msg.obj;
+ SomeArgs args = (SomeArgs) msg.obj;
+ InputChannel channel = (InputChannel) args.arg1;
+ ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2;
try {
TvInputSessionImpl sessionImpl = onCreateSession();
if (sessionImpl == null) {
// Failed to create a session.
cb.onSessionCreated(null);
- return;
+ } else {
+ ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this,
+ sessionImpl, channel);
+ cb.onSessionCreated(stub);
}
- ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this,
- sessionImpl);
- cb.onSessionCreated(stub);
} catch (RemoteException e) {
Log.e(TAG, "error in onSessionCreated");
}
+ args.recycle();
return;
}
case DO_BROADCAST_AVAILABILITY_CHANGE: {
diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java
index 325950d..289823b 100644
--- a/core/java/android/tv/TvView.java
+++ b/core/java/android/tv/TvView.java
@@ -20,20 +20,24 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
-import android.tv.TvInputManager;
import android.tv.TvInputManager.Session;
+import android.tv.TvInputManager.Session.FinishedInputEventCallback;
import android.tv.TvInputManager.SessionCreateCallback;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-import android.view.ViewTreeObserver;
/**
* View playing TV
*/
public class TvView extends SurfaceView {
+ // STOPSHIP: Turn debugging off.
+ private static final boolean DEBUG = true;
private static final String TAG = "TvView";
private final Handler mHandler = new Handler();
@@ -41,11 +45,11 @@
private Surface mSurface;
private boolean mOverlayViewCreated;
private Rect mOverlayViewFrame;
- private boolean mGlobalListenersAdded;
- private TvInputManager mTvInputManager;
+ private final TvInputManager mTvInputManager;
private SessionCreateCallback mSessionCreateCallback;
+ private OnUnhandledInputEventListener mOnUnhandledInputEventListener;
- private SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+ private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width=" + width
@@ -70,6 +74,25 @@
}
};
+ private final FinishedInputEventCallback mFinishedInputEventCallback =
+ new FinishedInputEventCallback() {
+ @Override
+ public void onFinishedInputEvent(Object token, boolean handled) {
+ if (DEBUG) {
+ Log.d(TAG, "onFinishedInputEvent(token=" + token + ", handled=" + handled + ")");
+ }
+ if (handled) {
+ return;
+ }
+ // TODO: Re-order unhandled events.
+ InputEvent event = (InputEvent) token;
+ if (dispatchUnhandledInputEvent(event)) {
+ return;
+ }
+ getViewRootImpl().dispatchUnhandledInputEvent(event);
+ }
+ };
+
public TvView(Context context) {
this(context, null, 0);
}
@@ -124,6 +147,98 @@
}
}
+ /**
+ * Dispatches an unhandled input event to the next receiver.
+ * <p>
+ * Except system keys, TvView always consumes input events in the normal flow. This is called
+ * asynchronously from where the event is dispatched. It gives the host application a chance to
+ * dispatch the unhandled input events.
+ *
+ * @param event The input event.
+ * @return {@code true} if the event was handled by the view, {@code false} otherwise.
+ */
+ public boolean dispatchUnhandledInputEvent(InputEvent event) {
+ if (mOnUnhandledInputEventListener != null) {
+ if (mOnUnhandledInputEventListener.onUnhandledInputEvent(event)) {
+ return true;
+ }
+ }
+ return onUnhandledInputEvent(event);
+ }
+
+ /**
+ * Called when an unhandled input event was also not handled by the user provided callback. This
+ * is the last chance to handle the unhandled input event in the TvView.
+ *
+ * @param event The input event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to be
+ * handled by the next receiver, return {@code false}.
+ */
+ public boolean onUnhandledInputEvent(InputEvent event) {
+ return false;
+ }
+
+ /**
+ * Registers a callback to be invoked when an input event was not handled by the bound TV input.
+ *
+ * @param listener The callback to invoke when the unhandled input event was received.
+ */
+ public void setOnUnhandledInputEventListener(OnUnhandledInputEventListener listener) {
+ mOnUnhandledInputEventListener = listener;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (super.dispatchKeyEvent(event)) {
+ return true;
+ }
+ if (DEBUG) Log.d(TAG, "dispatchKeyEvent(" + event + ")");
+ if (mSession == null) {
+ return false;
+ }
+ int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+ return ret != Session.DISPATCH_NOT_HANDLED;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ if (super.dispatchTouchEvent(event)) {
+ return true;
+ }
+ if (DEBUG) Log.d(TAG, "dispatchTouchEvent(" + event + ")");
+ if (mSession == null) {
+ return false;
+ }
+ int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+ return ret != Session.DISPATCH_NOT_HANDLED;
+ }
+
+ @Override
+ public boolean dispatchTrackballEvent(MotionEvent event) {
+ if (super.dispatchTrackballEvent(event)) {
+ return true;
+ }
+ if (DEBUG) Log.d(TAG, "dispatchTrackballEvent(" + event + ")");
+ if (mSession == null) {
+ return false;
+ }
+ int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+ return ret != Session.DISPATCH_NOT_HANDLED;
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ if (super.dispatchGenericMotionEvent(event)) {
+ return true;
+ }
+ if (DEBUG) Log.d(TAG, "dispatchGenericMotionEvent(" + event + ")");
+ if (mSession == null) {
+ return false;
+ }
+ int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+ return ret != Session.DISPATCH_NOT_HANDLED;
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -196,6 +311,23 @@
location[0] + getWidth(), location[1] + getHeight());
}
+ /**
+ * Interface definition for a callback to be invoked when the unhandled input event is received.
+ */
+ public interface OnUnhandledInputEventListener {
+ /**
+ * Called when an input event was not handled by the bound TV input.
+ * <p>
+ * This is called asynchronously from where the event is dispatched. It gives the host
+ * application a chance to handle the unhandled input events.
+ *
+ * @param event The input event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ boolean onUnhandledInputEvent(InputEvent event);
+ }
+
private class MySessionCreateCallback implements SessionCreateCallback {
final SessionCreateCallback mExternalCallback;
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 29c0ba2..aefced8 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -56,16 +56,18 @@
public static final class Event {
private final ByteBuffer mBuffer;
- // Layout of event log entry received from kernel.
+ // Layout of event log entry received from Android logger.
+ // see system/core/include/log/logger.h
private static final int LENGTH_OFFSET = 0;
+ private static final int HEADER_SIZE_OFFSET = 2;
private static final int PROCESS_OFFSET = 4;
private static final int THREAD_OFFSET = 8;
private static final int SECONDS_OFFSET = 12;
private static final int NANOSECONDS_OFFSET = 16;
- private static final int PAYLOAD_START = 20;
- private static final int TAG_OFFSET = 20;
- private static final int DATA_START = 24;
+ // Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET
+ private static final int V1_PAYLOAD_START = 20;
+ private static final int DATA_OFFSET = 4;
// Value types
private static final byte INT_TYPE = 0;
@@ -97,14 +99,22 @@
/** @return the type tag code of the entry */
public int getTag() {
- return mBuffer.getInt(TAG_OFFSET);
+ int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
+ if (offset == 0) {
+ offset = V1_PAYLOAD_START;
+ }
+ return mBuffer.getInt(offset);
}
/** @return one of Integer, Long, String, null, or Object[] of same. */
public synchronized Object getData() {
try {
- mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
- mBuffer.position(DATA_START); // Just after the tag.
+ int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
+ if (offset == 0) {
+ offset = V1_PAYLOAD_START;
+ }
+ mBuffer.limit(offset + mBuffer.getShort(LENGTH_OFFSET));
+ mBuffer.position(offset + DATA_OFFSET); // Just after the tag.
return decodeObject();
} catch (IllegalArgumentException e) {
Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index f0d8a61..34b85d9 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -1117,11 +1117,11 @@
}
@Override
- public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
+ public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ Paint paint) {
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
- nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
- rx, ry, paint.mNativePaint);
+ nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index d8d11f7..97339cc 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -555,7 +555,7 @@
}
@Override
- public void invokeFunctor(long functor, boolean waitForCompletion) {
+ void invokeFunctor(long functor, boolean waitForCompletion) {
boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
boolean hasContext = !needsContext;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 56d96e1..d31c79d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -453,7 +453,7 @@
* has invoked. If false, the functor may be invoked
* asynchronously.
*/
- public abstract void invokeFunctor(long functor, boolean waitForCompletion);
+ abstract void invokeFunctor(long functor, boolean waitForCompletion);
/**
* Initializes the hardware renderer for the specified surface and setup the
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 30e4281..3dc09c4 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -443,6 +443,14 @@
return nHasOverlappingRendering(mNativeRenderNode);
}
+ public void setElevation(float lift) {
+ nSetElevation(mNativeRenderNode, lift);
+ }
+
+ public float getElevation() {
+ return nGetElevation(mNativeRenderNode);
+ }
+
/**
* Sets the translation value for the display list on the X axis.
*
@@ -854,6 +862,7 @@
private static native void nSetAlpha(long renderNode, float alpha);
private static native void nSetHasOverlappingRendering(long renderNode,
boolean hasOverlappingRendering);
+ private static native void nSetElevation(long renderNode, float lift);
private static native void nSetTranslationX(long renderNode, float translationX);
private static native void nSetTranslationY(long renderNode, float translationY);
private static native void nSetTranslationZ(long renderNode, float translationZ);
@@ -874,6 +883,7 @@
private static native float nGetCameraDistance(long renderNode);
private static native float nGetScaleX(long renderNode);
private static native float nGetScaleY(long renderNode);
+ private static native float nGetElevation(long renderNode);
private static native float nGetTranslationX(long renderNode);
private static native float nGetTranslationY(long renderNode);
private static native float nGetTranslationZ(long renderNode);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 924c331..c7a6d41 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -217,7 +217,7 @@
}
@Override
- public void invokeFunctor(long functor, boolean waitForCompletion) {
+ void invokeFunctor(long functor, boolean waitForCompletion) {
nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cb05b05..76becda 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27,7 +27,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Interpolator;
@@ -2376,24 +2375,26 @@
static final int PFLAG3_CALLED_SUPER = 0x10;
/**
- * Flag indicating that an view will be clipped to its outline.
- */
- static final int PFLAG3_CLIP_TO_OUTLINE = 0x20;
-
- /**
* Flag indicating that a view's outline has been specifically defined.
*/
- static final int PFLAG3_OUTLINE_DEFINED = 0x40;
+ static final int PFLAG3_OUTLINE_DEFINED = 0x20;
/**
* Flag indicating that we're in the process of applying window insets.
*/
- static final int PFLAG3_APPLYING_INSETS = 0x80;
+ static final int PFLAG3_APPLYING_INSETS = 0x40;
/**
* Flag indicating that we're in the process of fitting system windows using the old method.
*/
- static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x100;
+ static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x80;
+
+ /**
+ * Flag indicating that nested scrolling is enabled for this view.
+ * The view will optionally cooperate with views up its parent chain to allow for
+ * integrated nested scrolling along the same axis.
+ */
+ static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x200;
/* End of masks for mPrivateFlags3 */
@@ -2847,6 +2848,21 @@
public static final int SCREEN_STATE_ON = 0x1;
/**
+ * Indicates no axis of view scrolling.
+ */
+ public static final int SCROLL_AXIS_NONE = 0;
+
+ /**
+ * Indicates scrolling along the horizontal axis.
+ */
+ public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0;
+
+ /**
+ * Indicates scrolling along the vertical axis.
+ */
+ public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
+
+ /**
* Controls the over-scroll mode for this view.
* See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
* {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS},
@@ -3237,9 +3253,7 @@
/**
* Stores the outline of the view, passed down to the DisplayList level for
- * defining shadow shape and clipping.
- *
- * TODO: once RenderNode is long-lived, remove this and rely on native copy.
+ * defining shadow shape.
*/
private Outline mOutline;
@@ -3473,6 +3487,14 @@
ViewOverlay mOverlay;
/**
+ * The currently active parent view for receiving delegated nested scrolling events.
+ * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared
+ * by {@link #stopNestedScroll()} at the same point where we clear
+ * requestDisallowInterceptTouchEvent.
+ */
+ private ViewParent mNestedScrollingParent;
+
+ /**
* Consistency verifier for debugging purposes.
* @hide
*/
@@ -3482,6 +3504,8 @@
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
+ private int[] mTempNestedScrollConsumed;
+
/**
* Simple constructor to use when creating a view from code.
*
@@ -3625,6 +3649,7 @@
float tx = 0;
float ty = 0;
float tz = 0;
+ float elevation = 0;
float rotation = 0;
float rotationX = 0;
float rotationY = 0;
@@ -3708,6 +3733,10 @@
tz = a.getDimensionPixelOffset(attr, 0);
transformSet = true;
break;
+ case com.android.internal.R.styleable.View_elevation:
+ elevation = a.getDimensionPixelOffset(attr, 0);
+ transformSet = true;
+ break;
case com.android.internal.R.styleable.View_rotation:
rotation = a.getFloat(attr, 0);
transformSet = true;
@@ -3963,6 +3992,9 @@
case R.styleable.View_sharedElementName:
setSharedElementName(a.getString(attr));
break;
+ case R.styleable.View_nestedScrollingEnabled:
+ setNestedScrollingEnabled(a.getBoolean(attr, false));
+ break;
}
}
@@ -4053,6 +4085,7 @@
setTranslationX(tx);
setTranslationY(ty);
setTranslationZ(tz);
+ setElevation(elevation);
setRotation(rotation);
setRotationX(rotationX);
setRotationY(rotationY);
@@ -7976,27 +8009,46 @@
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchTouchEvent(MotionEvent event) {
+ boolean result = false;
+
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
+ final int actionMasked = event.getActionMasked();
+ if (actionMasked == MotionEvent.ACTION_DOWN) {
+ // Defensive cleanup for new gesture
+ stopNestedScroll();
+ }
+
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
- if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
+ if (li != null && li.mOnTouchListener != null
+ && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
- return true;
+ result = true;
}
- if (onTouchEvent(event)) {
- return true;
+ if (!result && onTouchEvent(event)) {
+ result = true;
}
}
- if (mInputEventConsistencyVerifier != null) {
+ if (!result && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
- return false;
+
+ // Clean up after nested scrolls if this is the end of a gesture;
+ // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
+ // of the gesture.
+ if (actionMasked == MotionEvent.ACTION_UP ||
+ actionMasked == MotionEvent.ACTION_CANCEL ||
+ (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
+ stopNestedScroll();
+ }
+
+ return result;
}
/**
@@ -10389,6 +10441,48 @@
setTranslationY(y - mTop);
}
+ /**
+ * The visual z position of this view, in pixels. This is equivalent to the
+ * {@link #setTranslationZ(float) translationZ} property plus the current
+ * {@link #getElevation() elevation} property.
+ *
+ * @return The visual z position of this view, in pixels.
+ */
+ @ViewDebug.ExportedProperty(category = "drawing")
+ public float getZ() {
+ return getElevation() + getTranslationZ();
+ }
+
+ /**
+ * Sets the visual z position of this view, in pixels. This is equivalent to setting the
+ * {@link #setTranslationZ(float) translationZ} property to be the difference between
+ * the x value passed in and the current {@link #getElevation() elevation} property.
+ *
+ * @param z The visual z position of this view, in pixels.
+ */
+ public void setZ(float z) {
+ setTranslationZ(z - getElevation());
+ }
+
+ @ViewDebug.ExportedProperty(category = "drawing")
+ public float getElevation() {
+ return mRenderNode.getElevation();
+ }
+
+ /**
+ * Sets the base depth location of this view.
+ *
+ * @attr ref android.R.styleable#View_elevation
+ */
+ public void setElevation(float elevation) {
+ if (elevation != getElevation()) {
+ invalidateViewProperty(true, false);
+ mRenderNode.setElevation(elevation);
+ invalidateViewProperty(false, true);
+
+ invalidateParentIfNeededAndWasQuickRejected();
+ }
+ }
/**
* The horizontal location of this view relative to its {@link #getLeft() left} position.
@@ -10456,9 +10550,9 @@
}
/**
- * The depth location of this view relative to its parent.
+ * The depth location of this view relative to its {@link #getElevation() elevation}.
*
- * @return The depth of this view relative to its parent.
+ * @return The depth of this view relative to its elevation.
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationZ() {
@@ -10466,7 +10560,7 @@
}
/**
- * Sets the depth location of this view relative to its parent.
+ * Sets the depth location of this view relative to its {@link #getElevation() elevation}.
*
* @attr ref android.R.styleable#View_translationZ
*/
@@ -10519,16 +10613,13 @@
/**
* Sets the outline of the view, which defines the shape of the shadow it
- * casts, and can used for clipping.
+ * casts.
* <p>
* If the outline is not set or is null, shadows will be cast from the
- * bounds of the View, and clipToOutline will be ignored.
+ * bounds of the View.
*
* @param outline The new outline of the view.
* Must be {@link android.graphics.Outline#isValid() valid.}
- *
- * @see #getClipToOutline()
- * @see #setClipToOutline(boolean)
*/
public void setOutline(@Nullable Outline outline) {
if (outline != null && !outline.isValid()) {
@@ -10549,39 +10640,27 @@
mRenderNode.setOutline(mOutline);
}
- /**
- * Returns whether the outline of the View will be used for clipping.
- *
- * @see #setOutline(Outline)
- */
- public final boolean getClipToOutline() {
- return ((mPrivateFlags3 & PFLAG3_CLIP_TO_OUTLINE) != 0);
- }
+ // TODO: remove
+ public final boolean getClipToOutline() { return false; }
+ public void setClipToOutline(boolean clipToOutline) {}
- /**
- * Sets whether the outline of the View will be used for clipping.
- * <p>
- * The current implementation of outline clipping uses
- * {@link Canvas#clipPath(Path) path clipping},
- * and thus does not support anti-aliasing, and is expensive in terms of
- * graphics performance. Therefore, it is strongly recommended that this
- * property only be set temporarily, as in an animation. For the same
- * reasons, there is no parallel XML attribute for this property.
- * <p>
- * If the outline of the view is not set or is empty, no clipping will be
- * performed.
- *
- * @see #setOutline(Outline)
- */
- public void setClipToOutline(boolean clipToOutline) {
- // TODO : Add a fast invalidation here.
- if (getClipToOutline() != clipToOutline) {
- if (clipToOutline) {
- mPrivateFlags3 |= PFLAG3_CLIP_TO_OUTLINE;
+ private void queryOutlineFromBackgroundIfUndefined() {
+ if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
+ // Outline not currently defined, query from background
+ if (mOutline == null) {
+ mOutline = new Outline();
} else {
- mPrivateFlags3 &= ~PFLAG3_CLIP_TO_OUTLINE;
+ //invalidate outline, to ensure background calculates it
+ mOutline.set(null);
}
- mRenderNode.setClipToOutline(clipToOutline);
+ if (mBackground.getOutline(mOutline)) {
+ if (!mOutline.isValid()) {
+ throw new IllegalStateException("Background drawable failed to build outline");
+ }
+ mRenderNode.setOutline(mOutline);
+ } else {
+ mRenderNode.setOutline(null);
+ }
}
}
@@ -11154,7 +11233,7 @@
}
// Damage the entire IsolatedZVolume recieving this view's shadow.
- if (isHardwareAccelerated() && getTranslationZ() != 0) {
+ if (isHardwareAccelerated() && getZ() != 0) {
damageShadowReceiver();
}
}
@@ -11230,7 +11309,7 @@
} else {
damageInParent();
}
- if (isHardwareAccelerated() && invalidateParent && getTranslationZ() != 0) {
+ if (isHardwareAccelerated() && invalidateParent && getZ() != 0) {
damageShadowReceiver();
}
}
@@ -12731,10 +12810,15 @@
mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
+ if (mBackground != null) {
+ mBackground.clearHotspots();
+ }
+
removeUnsetPressCallback();
removeLongPressCallback();
removePerformClickCallback();
removeSendViewScrolledAccessibilityEventCallback();
+ stopNestedScroll();
destroyDrawingCache();
destroyLayer(false);
@@ -14839,11 +14923,7 @@
if (mBackgroundSizeChanged) {
background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
mBackgroundSizeChanged = false;
- if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
- // Outline not currently define, query from background
- mOutline = background.getOutline();
- mRenderNode.setOutline(mOutline);
- }
+ queryOutlineFromBackgroundIfUndefined();
}
// Attempt to use a display list if requested.
@@ -15245,7 +15325,7 @@
* @param drawable the drawable to invalidate
*/
@Override
- public void invalidateDrawable(Drawable drawable) {
+ public void invalidateDrawable(@NonNull Drawable drawable) {
if (verifyDrawable(drawable)) {
final Rect dirty = drawable.getDirtyBounds();
final int scrollX = mScrollX;
@@ -15253,6 +15333,10 @@
invalidate(dirty.left + scrollX, dirty.top + scrollY,
dirty.right + scrollX, dirty.bottom + scrollY);
+
+ if (drawable == mBackground) {
+ queryOutlineFromBackgroundIfUndefined();
+ }
}
}
@@ -17901,6 +17985,249 @@
}
/**
+ * Enable or disable nested scrolling for this view.
+ *
+ * <p>If this property is set to true the view will be permitted to initiate nested
+ * scrolling operations with a compatible parent view in the current hierarchy. If this
+ * view does not implement nested scrolling this will have no effect.</p>
+ *
+ * @param enabled true to enable nested scrolling, false to disable
+ *
+ * @see #isNestedScrollingEnabled()
+ */
+ public void setNestedScrollingEnabled(boolean enabled) {
+ if (enabled) {
+ mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED;
+ } else {
+ mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED;
+ }
+ }
+
+ /**
+ * Returns true if nested scrolling is enabled for this view.
+ *
+ * <p>If nested scrolling is enabled and this View class implementation supports it,
+ * this view will act as a nested scrolling child view when applicable, forwarding data
+ * about the scroll operation in progress to a compatible and cooperating nested scrolling
+ * parent.</p>
+ *
+ * @return true if nested scrolling is enabled
+ *
+ * @see #setNestedScrollingEnabled(boolean)
+ */
+ public boolean isNestedScrollingEnabled() {
+ return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) ==
+ PFLAG3_NESTED_SCROLLING_ENABLED;
+ }
+
+ /**
+ * Begin a nestable scroll operation along the given axes.
+ *
+ * <p>A view starting a nested scroll promises to abide by the following contract:</p>
+ *
+ * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case
+ * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}.
+ * In the case of touch scrolling the nested scroll will be terminated automatically in
+ * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}.
+ * In the event of programmatic scrolling the caller must explicitly call
+ * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p>
+ *
+ * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found.
+ * If it returns false the caller may ignore the rest of this contract until the next scroll.
+ * Calling startNestedScroll while a nested scroll is already in progress will return true.</p>
+ *
+ * <p>At each incremental step of the scroll the caller should invoke
+ * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll}
+ * once it has calculated the requested scrolling delta. If it returns true the nested scrolling
+ * parent at least partially consumed the scroll and the caller should adjust the amount it
+ * scrolls by.</p>
+ *
+ * <p>After applying the remainder of the scroll delta the caller should invoke
+ * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing
+ * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat
+ * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}.
+ * </p>
+ *
+ * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or
+ * {@link #SCROLL_AXIS_VERTICAL}.
+ * @return true if a cooperative parent was found and nested scrolling has been enabled for
+ * the current gesture.
+ *
+ * @see #stopNestedScroll()
+ * @see #dispatchNestedPreScroll(int, int, int[], int[])
+ * @see #dispatchNestedScroll(int, int, int, int, int[])
+ */
+ public boolean startNestedScroll(int axes) {
+ if (hasNestedScrollingParent()) {
+ // Already in progress
+ return true;
+ }
+ if (isNestedScrollingEnabled()) {
+ ViewParent p = getParent();
+ View child = this;
+ while (p != null) {
+ try {
+ if (p.onStartNestedScroll(child, this, axes)) {
+ mNestedScrollingParent = p;
+ p.onNestedScrollAccepted(child, this, axes);
+ return true;
+ }
+ } catch (AbstractMethodError e) {
+ Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " +
+ "method onStartNestedScroll", e);
+ // Allow the search upward to continue
+ }
+ if (p instanceof View) {
+ child = (View) p;
+ }
+ p = p.getParent();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Stop a nested scroll in progress.
+ *
+ * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p>
+ *
+ * @see #startNestedScroll(int)
+ */
+ public void stopNestedScroll() {
+ if (mNestedScrollingParent != null) {
+ mNestedScrollingParent.onStopNestedScroll(this);
+ mNestedScrollingParent = null;
+ }
+ }
+
+ /**
+ * Returns true if this view has a nested scrolling parent.
+ *
+ * <p>The presence of a nested scrolling parent indicates that this view has initiated
+ * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p>
+ *
+ * @return whether this view has a nested scrolling parent
+ */
+ public boolean hasNestedScrollingParent() {
+ return mNestedScrollingParent != null;
+ }
+
+ /**
+ * Dispatch one step of a nested scroll in progress.
+ *
+ * <p>Implementations of views that support nested scrolling should call this to report
+ * info about a scroll in progress to the current nested scrolling parent. If a nested scroll
+ * is not currently in progress or nested scrolling is not
+ * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p>
+ *
+ * <p>Compatible View implementations should also call
+ * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before
+ * consuming a component of the scroll event themselves.</p>
+ *
+ * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step
+ * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step
+ * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view
+ * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view
+ * @param offsetInWindow Optional. If not null, on return this will contain the offset
+ * in local view coordinates of this view from before this operation
+ * to after it completes. View implementations may use this to adjust
+ * expected input coordinate tracking.
+ * @return true if the event was dispatched, false if it could not be dispatched.
+ * @see #dispatchNestedPreScroll(int, int, int[], int[])
+ */
+ public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
+ if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
+ int startX = 0;
+ int startY = 0;
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ startX = offsetInWindow[0];
+ startY = offsetInWindow[1];
+ }
+
+ mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed,
+ dxUnconsumed, dyUnconsumed);
+
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ offsetInWindow[0] -= startX;
+ offsetInWindow[1] -= startY;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Dispatch one step of a nested scroll in progress before this view consumes any portion of it.
+ *
+ * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch.
+ * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested
+ * scrolling operation to consume some or all of the scroll operation before the child view
+ * consumes it.</p>
+ *
+ * @param dx Horizontal scroll distance in pixels
+ * @param dy Vertical scroll distance in pixels
+ * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx
+ * and consumed[1] the consumed dy.
+ * @param offsetInWindow Optional. If not null, on return this will contain the offset
+ * in local view coordinates of this view from before this operation
+ * to after it completes. View implementations may use this to adjust
+ * expected input coordinate tracking.
+ * @return true if the parent consumed some or all of the scroll delta
+ * @see #dispatchNestedScroll(int, int, int, int, int[])
+ */
+ public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+ if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
+ int startX = 0;
+ int startY = 0;
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ startX = offsetInWindow[0];
+ startY = offsetInWindow[1];
+ }
+
+ if (consumed == null) {
+ if (mTempNestedScrollConsumed == null) {
+ mTempNestedScrollConsumed = new int[2];
+ }
+ consumed = mTempNestedScrollConsumed;
+ }
+ consumed[0] = 0;
+ consumed[1] = 0;
+ mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed);
+
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ offsetInWindow[0] -= startX;
+ offsetInWindow[1] -= startY;
+ }
+ return consumed[0] != 0 || consumed[1] != 0;
+ }
+ return false;
+ }
+
+ /**
+ * Dispatch a fling to a nested scrolling parent.
+ *
+ * <p>If a nested scrolling child view would normally fling but it is at the edge of its
+ * own content it should use this method to delegate the fling to its nested scrolling parent.
+ * The view implementation can use a {@link VelocityTracker} to obtain the velocity values
+ * to pass.</p>
+ *
+ * @param velocityX Horizontal fling velocity in pixels per second
+ * @param velocityY Vertical fling velocity in pixels per second
+ * @return true if the nested scrolling parent consumed the fling
+ */
+ public boolean dispatchNestedFling(float velocityX, float velocityY) {
+ if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
+ return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY);
+ }
+ return false;
+ }
+
+ /**
* Gets a scale factor that determines the distance the view should scroll
* vertically in response to {@link MotionEvent#ACTION_SCROLL}.
* @return The vertical scroll scale factor.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9d4ffb1..8865ab4 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -460,6 +460,13 @@
@ViewDebug.ExportedProperty(category = "layout")
private int mChildCountWithTransientState = 0;
+ /**
+ * Currently registered axes for nested scrolling. Flag set consisting of
+ * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
+ * for null.
+ */
+ private int mNestedScrollAxes;
+
public ViewGroup(Context context) {
this(context, null);
}
@@ -2011,6 +2018,7 @@
clearTouchTargets();
resetCancelNextUpFlag(this);
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
+ mNestedScrollAxes = SCROLL_AXIS_NONE;
}
/**
@@ -2334,6 +2342,7 @@
if (disallowIntercept) {
mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
+ stopNestedScroll();
} else {
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
@@ -5856,6 +5865,74 @@
return true;
}
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int axes) {
+ mNestedScrollAxes = axes;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * <p>The default implementation of onStopNestedScroll calls
+ * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
+ */
+ @Override
+ public void onStopNestedScroll(View child) {
+ // Stop any recursive nested scrolling.
+ stopNestedScroll();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed) {
+ // Do nothing
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+ // Do nothing
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY) {
+ return false;
+ }
+
+ /**
+ * Return the current axes of nested scrolling for this ViewGroup.
+ *
+ * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
+ * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
+ *
+ * @return Flags indicating the current axes of nested scrolling
+ * @see #SCROLL_AXIS_HORIZONTAL
+ * @see #SCROLL_AXIS_VERTICAL
+ * @see #SCROLL_AXIS_NONE
+ */
+ public int getNestedScrollAxes() {
+ return mNestedScrollAxes;
+ }
+
/** @hide */
protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 01376934..3cd6449 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -407,4 +407,119 @@
* {@link View#TEXT_ALIGNMENT_VIEW_END}
*/
public int getTextAlignment();
+
+ /**
+ * React to a descendant view initiating a nestable scroll operation, claiming the
+ * nested scroll operation if appropriate.
+ *
+ * <p>This method will be called in response to a descendant view invoking
+ * {@link View#startNestedScroll(int)}. Each parent up the view hierarchy will be
+ * given an opportunity to respond and claim the nested scrolling operation by returning
+ * <code>true</code>.</p>
+ *
+ * <p>This method may be overridden by ViewParent implementations to indicate when the view
+ * is willing to support a nested scrolling operation that is about to begin. If it returns
+ * true, this ViewParent will become the target view's nested scrolling parent for the duration
+ * of the scroll operation in progress. When the nested scroll is finished this ViewParent
+ * will receive a call to {@link #onStopNestedScroll(View)}.
+ * </p>
+ *
+ * @param child Direct child of this ViewParent containing target
+ * @param target View that initiated the nested scroll
+ * @param nestedScrollAxes Flags consisting of {@link View#SCROLL_AXIS_HORIZONTAL},
+ * {@link View#SCROLL_AXIS_VERTICAL} or both
+ * @return true if this ViewParent accepts the nested scroll operation
+ */
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);
+
+ /**
+ * React to the successful claiming of a nested scroll operation.
+ *
+ * <p>This method will be called after
+ * {@link #onStartNestedScroll(View, View, int) onStartNestedScroll} returns true. It offers
+ * an opportunity for the view and its superclasses to perform initial configuration
+ * for the nested scroll. Implementations of this method should always call their superclass's
+ * implementation of this method if one is present.</p>
+ *
+ * @param child Direct child of this ViewParent containing target
+ * @param target View that initiated the nested scroll
+ * @param nestedScrollAxes Flags consisting of {@link View#SCROLL_AXIS_HORIZONTAL},
+ * {@link View#SCROLL_AXIS_VERTICAL} or both
+ * @see #onStartNestedScroll(View, View, int)
+ * @see #onStopNestedScroll(View)
+ */
+ public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);
+
+ /**
+ * React to a nested scroll operation ending.
+ *
+ * <p>Perform cleanup after a nested scrolling operation.
+ * This method will be called when a nested scroll stops, for example when a nested touch
+ * scroll ends with a {@link MotionEvent#ACTION_UP} or {@link MotionEvent#ACTION_CANCEL} event.
+ * Implementations of this method should always call their superclass's implementation of this
+ * method if one is present.</p>
+ *
+ * @param target View that initiated the nested scroll
+ */
+ public void onStopNestedScroll(View target);
+
+ /**
+ * React to a nested scroll in progress.
+ *
+ * <p>This method will be called when the ViewParent's current nested scrolling child view
+ * dispatches a nested scroll event. To receive calls to this method the ViewParent must have
+ * previously returned <code>true</code> for a call to
+ * {@link #onStartNestedScroll(View, View, int)}.</p>
+ *
+ * <p>Both the consumed and unconsumed portions of the scroll distance are reported to the
+ * ViewParent. An implementation may choose to use the consumed portion to match or chase scroll
+ * position of multiple child elements, for example. The unconsumed portion may be used to
+ * allow continuous dragging of multiple scrolling or draggable elements, such as scrolling
+ * a list within a vertical drawer where the drawer begins dragging once the edge of inner
+ * scrolling content is reached.</p>
+ *
+ * @param target The descendent view controlling the nested scroll
+ * @param dxConsumed Horizontal scroll distance in pixels already consumed by target
+ * @param dyConsumed Vertical scroll distance in pixels already consumed by target
+ * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by target
+ * @param dyUnconsumed Vertical scroll distance in pixels not consumed by target
+ */
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed);
+
+ /**
+ * React to a nested scroll in progress before the target view consumes a portion of the scroll.
+ *
+ * <p>When working with nested scrolling often the parent view may want an opportunity
+ * to consume the scroll before the nested scrolling child does. An example of this is a
+ * drawer that contains a scrollable list. The user will want to be able to scroll the list
+ * fully into view before the list itself begins scrolling.</p>
+ *
+ * <p><code>onNestedPreScroll</code> is called when a nested scrolling child invokes
+ * {@link View#dispatchNestedPreScroll(int, int, int[], int[])}. The implementation should
+ * report how any pixels of the scroll reported by dx, dy were consumed in the
+ * <code>consumed</code> array. Index 0 corresponds to dx and index 1 corresponds to dy.
+ * This parameter will never be null. Initial values for consumed[0] and consumed[1]
+ * will always be 0.</p>
+ *
+ * @param target View that initiated the nested scroll
+ * @param dx Horizontal scroll distance in pixels
+ * @param dy Vertical scroll distance in pixels
+ * @param consumed Output. The horizontal and vertical scroll distance consumed by this parent
+ */
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);
+
+ /**
+ * Request a fling from a nested scroll.
+ *
+ * <p>If a nested scrolling child view would normally fling but it is at the edge of
+ * its own content, it can delegate the fling to its nested scrolling parent instead.
+ * This method allows the parent to optionally consume the fling.</p>
+ *
+ * @param target View that initiated the nested scroll
+ * @param velocityX Horizontal velocity in pixels per second.
+ * @param velocityY Vertical velocity in pixels per second
+ * @return true if this parent consumed the fling
+ */
+ public boolean onNestedFling(View target, float velocityX, float velocityY);
}
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 6b21451..b1aa7b2 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -144,10 +144,11 @@
private static final int ROTATION_Y = 0x0080;
private static final int X = 0x0100;
private static final int Y = 0x0200;
- private static final int ALPHA = 0x0400;
+ private static final int Z = 0x0400;
+ private static final int ALPHA = 0x0800;
private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
- SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y;
+ SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y | Z;
/**
* The mechanism by which the user can request several properties that are then animated
@@ -470,6 +471,32 @@
}
/**
+ * This method will cause the View's <code>z</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setZ(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator z(float value) {
+ animateProperty(Z, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>z</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setZ(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator zBy(float value) {
+ animatePropertyBy(Z, value);
+ return this;
+ }
+
+ /**
* This method will cause the View's <code>rotation</code> property to be animated to the
* specified value. Animations already running on the property will be canceled.
*
@@ -957,6 +984,9 @@
case Y:
renderNode.setTranslationY(value - mView.mTop);
break;
+ case Z:
+ renderNode.setTranslationZ(value - renderNode.getElevation());
+ break;
case ALPHA:
info.mAlpha = value;
renderNode.setAlpha(value);
@@ -993,6 +1023,8 @@
return mView.mLeft + node.getTranslationX();
case Y:
return mView.mTop + node.getTranslationY();
+ case Z:
+ return node.getElevation() + node.getTranslationZ();
case ALPHA:
return mView.mTransformationInfo.mAlpha;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 23be203..14e422c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -678,6 +678,14 @@
}
}
+ public boolean invokeFunctor(long functor, boolean waitForCompletion) {
+ if (mAttachInfo.mHardwareRenderer == null || !mAttachInfo.mHardwareRenderer.isEnabled()) {
+ return false;
+ }
+ mAttachInfo.mHardwareRenderer.invokeFunctor(functor, waitForCompletion);
+ return true;
+ }
+
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
@@ -3204,8 +3212,11 @@
doDie();
break;
case MSG_DISPATCH_INPUT_EVENT: {
- InputEvent event = (InputEvent)msg.obj;
- enqueueInputEvent(event, null, 0, true);
+ SomeArgs args = (SomeArgs)msg.obj;
+ InputEvent event = (InputEvent)args.arg1;
+ InputEventReceiver receiver = (InputEventReceiver)args.arg2;
+ enqueueInputEvent(event, receiver, 0, true);
+ args.recycle();
} break;
case MSG_DISPATCH_KEY_FROM_IME: {
if (LOCAL_LOGV) Log.v(
@@ -5787,7 +5798,14 @@
}
public void dispatchInputEvent(InputEvent event) {
- Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, event);
+ dispatchInputEvent(event, null);
+ }
+
+ public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = event;
+ args.arg2 = receiver;
+ Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
@@ -6090,6 +6108,33 @@
// Do nothing.
}
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return false;
+ }
+
+ @Override
+ public void onStopNestedScroll(View target) {
+ }
+
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
+ }
+
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed) {
+ }
+
+ @Override
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+ }
+
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY) {
+ return false;
+ }
+
void changeCanvasOpacity(boolean opaque) {
// TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e3bd9fd..0227873 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -317,6 +317,10 @@
int mCursorSelEnd;
int mCursorCandStart;
int mCursorCandEnd;
+ /**
+ * The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}.
+ */
+ private final int[] mViewTopLeft = new int[2];
// -----------------------------------------------------------
@@ -1487,12 +1491,26 @@
return false;
}
synchronized (mH) {
- return mCursorAnchorMonitorMode ==
- InputMethodService.CURSOR_ANCHOR_MONITOR_MODE_CURSOR_RECT;
+ return (mCursorAnchorMonitorMode &
+ InputMethodService.CURSOR_ANCHOR_MONITOR_MODE_CURSOR_RECT) != 0;
}
}
/**
+ * Returns true if the current input method wants to receive the cursor rectangle in
+ * screen coordinates rather than local coordinates in the attached view.
+ *
+ * @hide
+ */
+ public boolean usesScreenCoordinatesForCursorLocked() {
+ // {@link InputMethodService#CURSOR_ANCHOR_MONITOR_MODE_CURSOR_RECT} also means
+ // that {@link InputMethodService#onUpdateCursor} should provide the cursor rectangle
+ // in screen coordinates rather than local coordinates.
+ return (mCursorAnchorMonitorMode &
+ InputMethodService.CURSOR_ANCHOR_MONITOR_MODE_CURSOR_RECT) != 0;
+ }
+
+ /**
* Set cursor/anchor monitor mode via {@link com.android.server.InputMethodManagerService}.
* This is an internal method for {@link android.inputmethodservice.InputMethodService} and
* should never be used from IMEs and applications.
@@ -1518,15 +1536,18 @@
|| mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
-
mTmpCursorRect.set(left, top, right, bottom);
if (!mCursorRect.equals(mTmpCursorRect)) {
if (DEBUG) Log.d(TAG, "updateCursor");
try {
if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
- mCurMethod.updateCursor(mTmpCursorRect);
mCursorRect.set(mTmpCursorRect);
+ if (usesScreenCoordinatesForCursorLocked()) {
+ view.getLocationOnScreen(mViewTopLeft);
+ mTmpCursorRect.offset(mViewTopLeft[0], mViewTopLeft[1]);
+ }
+ mCurMethod.updateCursor(mTmpCursorRect);
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
new file mode 100644
index 0000000..8951786
--- /dev/null
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.webkit;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * ClientCertRequest: The user receives an instance of this class as
+ * a parameter of {@link WebViewClient#onReceivedClientCertRequest}.
+ * The request includes the parameters to choose the client certificate,
+ * such as the host name and the port number requesting the cert, the acceptable
+ * key types and the principals.
+ *
+ * The user should call one of the interface methods to indicate how to deal
+ * with the client certificate request. All methods should be called on
+ * UI thread.
+ *
+ * WebView caches the {@link #proceed} and {@link #cancel} responses in memory
+ * and uses them to handle future client certificate requests for the same
+ * host/port pair. The user can clear the cached data using
+ * {@link WebView#clearClientCertPreferences}.
+ *
+ * TODO(sgurun) unhide
+ * @hide
+ */
+public interface ClientCertRequest {
+ /**
+ * Returns the acceptable types of asymmetric keys (can be null).
+ */
+ public String[] getKeyTypes();
+
+ /**
+ * Returns the acceptable certificate issuers for the certificate
+ * matching the private key (can be null).
+ */
+ public Principal[] getPrincipals();
+
+ /**
+ * Returns the host name of the server requesting the certificate.
+ */
+ public String getHost();
+
+ /**
+ * Returns the port number of the server requesting the certificate.
+ */
+ public int getPort();
+
+ /**
+ * Proceed with the specified private key and client certificate chain.
+ * Remember the user's positive choice and use it for future requests.
+ */
+ public void proceed(PrivateKey privateKey, X509Certificate[] chain);
+
+ /**
+ * Ignore the request for now. Do not remember user's choice.
+ */
+ public void ignore();
+
+ /**
+ * Cancel this request. Remember the user's choice and use it for
+ * future requests.
+ */
+ public void cancel();
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index d2e7324..c914e52 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -485,7 +485,7 @@
* @param privateBrowsing whether this WebView will be initialized in
* private mode
*
- * @deprecated Private browsing is no longer supported directly via
+ * @deprecated Private browsing is no longer supported directly via
* WebView and will be removed in a future release. Prefer using
* {@link WebSettings}, {@link WebViewDatabase}, {@link CookieManager}
* and {@link WebStorage} for fine-grained control of privacy data.
@@ -1476,6 +1476,24 @@
}
/**
+ * Clears the client certificate preferences table stored in response
+ * to proceeding/cancelling client cert requests. Note that webview
+ * automatically clears these preferences when it receives a
+ * {@link KeyChain.ACTION_STORAGE_CHANGED}
+ *
+ * @param resultCallback A callback to be invoked when client certs are cleared.
+ * The embedder can pass null if not interested in the callback.
+ *
+ * TODO(sgurun) unhide
+ * @hide
+ */
+ public void clearClientCertPreferences(ValueCallback<Void> resultCallback) {
+ checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearClientCertPreferences");
+ mProvider.clearClientCertPreferences(resultCallback);
+ }
+
+ /**
* Gets the WebBackForwardList for this WebView. This contains the
* back/forward list for use in querying each item in the history stack.
* This is a copy of the private WebBackForwardList so it contains only a
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index e8974c6..688c251 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -22,6 +22,8 @@
import android.view.KeyEvent;
import android.view.ViewRootImpl;
+import java.security.Principal;
+
public class WebViewClient {
/**
@@ -205,6 +207,30 @@
}
/**
+ * Notify the host application to handle a SSL client certificate
+ * request. The host application is responsible for showing the UI
+ * if desired and providing the keys. There are three ways to
+ * respond: proceed(), cancel() or ignore(). Webview remembers the
+ * response if proceed() or cancel() is called and does not
+ * call onReceivedClientCertRequest() again for the same host and port
+ * pair. Webview does not remember the response if ignore() is called.
+ *
+ * This method is called on the UI thread. During the callback, the
+ * connection is suspended.
+ *
+ * The default behavior is to cancel, returning no client certificate.
+ *
+ * @param view The WebView that is initiating the callback
+ * @param request An instance of a {@link ClientCertRequest}
+ *
+ * TODO(sgurun) unhide
+ * @hide
+ */
+ public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
+ request.cancel();
+ }
+
+ /**
* Notifies the host application that the WebView received an HTTP
* authentication request. The host application can use the supplied
* {@link HttpAuthHandler} to set the WebView's response to the request.
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 5081ff5..efa5497 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -198,6 +198,8 @@
public void clearSslPreferences();
+ public void clearClientCertPreferences(ValueCallback<Void> resultCallback);
+
public WebBackForwardList copyBackForwardList();
public void setFindListener(WebView.FindListener listener);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 301317e..becda67 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -543,7 +543,7 @@
/**
* The last CheckForTap runnable we posted, if any
*/
- private Runnable mPendingCheckForTap;
+ private CheckForTap mPendingCheckForTap;
/**
* The last CheckForKeyLongPress runnable we posted, if any
@@ -2126,7 +2126,9 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
+
mInLayout = true;
+
final int childCount = getChildCount();
if (changed) {
for (int i = 0; i < childCount; i++) {
@@ -3185,7 +3187,10 @@
return INVALID_ROW_ID;
}
- final class CheckForTap implements Runnable {
+ private final class CheckForTap implements Runnable {
+ float x;
+ float y;
+
@Override
public void run() {
if (mTouchMode == TOUCH_MODE_DOWN) {
@@ -3205,7 +3210,7 @@
final boolean longClickable = isLongClickable();
if (mSelector != null) {
- Drawable d = mSelector.getCurrent();
+ final Drawable d = mSelector.getCurrent();
if (d != null && d instanceof TransitionDrawable) {
if (longClickable) {
((TransitionDrawable) d).startTransition(longPressTimeout);
@@ -3213,6 +3218,9 @@
((TransitionDrawable) d).resetTransition();
}
}
+ if (d.supportsHotspots()) {
+ d.setHotspot(R.attr.state_pressed, x, y);
+ }
}
if (longClickable) {
@@ -3596,6 +3604,8 @@
mPendingCheckForTap = new CheckForTap();
}
+ mPendingCheckForTap.x = ev.getX();
+ mPendingCheckForTap.y = ev.getY();
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
}
}
@@ -3705,6 +3715,9 @@
if (d != null && d instanceof TransitionDrawable) {
((TransitionDrawable) d).resetTransition();
}
+ if (mSelector.supportsHotspots()) {
+ mSelector.setHotspot(R.attr.state_pressed, x, ev.getY());
+ }
}
if (mTouchModeReset != null) {
removeCallbacks(mTouchModeReset);
@@ -3716,6 +3729,9 @@
mTouchMode = TOUCH_MODE_REST;
child.setPressed(false);
setPressed(false);
+ if (mSelector != null && mSelector.supportsHotspots()) {
+ mSelector.removeHotspot(R.attr.state_pressed);
+ }
if (!mDataChanged && !mIsDetaching && isAttachedToWindow()) {
performClick.run();
}
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 74b41c9..0c31496 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -256,6 +256,16 @@
}
}
+ /**
+ * Assigns the drawable that is to be drawn on top of the assigned contact photo.
+ *
+ * @param overlay Drawable to be drawn over the assigned contact photo. Must have a non-zero
+ * instrinsic width and height.
+ */
+ public void setOverlay(Drawable overlay) {
+ mOverlay = overlay;
+ }
+
private void onContactUriChanged() {
setEnabled(isAssigned());
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 082d728..7e8f6b4 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -138,6 +138,12 @@
private int mActivePointerId = INVALID_POINTER;
/**
+ * Used during scrolling to retrieve the new offset within the window.
+ */
+ private final int[] mScrollOffset = new int[2];
+ private final int[] mScrollConsumed = new int[2];
+
+ /**
* The StrictMode "critical time span" objects to catch animation
* stutters. Non-null when a time-sensitive animation is
* in-flight. Must call finish() on them when done animating.
@@ -505,7 +511,7 @@
final int y = (int) ev.getY(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
- if (yDiff > mTouchSlop) {
+ if (yDiff > mTouchSlop && (getNestedScrollAxes() & SCROLL_AXIS_VERTICAL) == 0) {
mIsBeingDragged = true;
mLastMotionY = y;
initVelocityTrackerIfNotExists();
@@ -547,6 +553,7 @@
if (mIsBeingDragged && mScrollStrictSpan == null) {
mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
}
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
break;
}
@@ -559,6 +566,7 @@
if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
postInvalidateOnAnimation();
}
+ stopNestedScroll();
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
@@ -606,6 +614,7 @@
// Remember where the motion event started
mLastMotionY = (int) ev.getY();
mActivePointerId = ev.getPointerId(0);
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
break;
}
case MotionEvent.ACTION_MOVE:
@@ -617,6 +626,9 @@
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
+ if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
+ deltaY -= mScrollConsumed[1] + mScrollOffset[1];
+ }
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
final ViewParent parent = getParent();
if (parent != null) {
@@ -633,22 +645,25 @@
// Scroll to follow the motion event
mLastMotionY = y;
- final int oldX = mScrollX;
final int oldY = mScrollY;
final int range = getScrollRange();
final int overscrollMode = getOverScrollMode();
- final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+ boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
// Calling overScrollBy will call onOverScrolled, which
// calls onScrollChanged if applicable.
- if (overScrollBy(0, deltaY, 0, mScrollY,
- 0, range, 0, mOverscrollDistance, true)) {
+ if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true)
+ && !hasNestedScrollingParent()) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
- if (canOverscroll) {
+ final int scrolledDeltaY = mScrollY - oldY;
+ final int unconsumedY = deltaY - scrolledDeltaY;
+ if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset)) {
+ mLastMotionY -= mScrollOffset[1];
+ } else if (canOverscroll) {
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
mEdgeGlowTop.onPull((float) deltaY / getHeight());
@@ -674,15 +689,11 @@
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
- if (getChildCount() > 0) {
- if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
- fling(-initialVelocity);
- } else {
- if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0,
- getScrollRange())) {
- postInvalidateOnAnimation();
- }
- }
+ if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
+ flingWithNestedDispatch(-initialVelocity);
+ } else if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0,
+ getScrollRange())) {
+ postInvalidateOnAnimation();
}
mActivePointerId = INVALID_POINTER;
@@ -1553,6 +1564,15 @@
}
}
+ private void flingWithNestedDispatch(int velocityY) {
+ if (mScrollY == 0 && velocityY < 0 ||
+ mScrollY == getScrollRange() && velocityY > 0) {
+ dispatchNestedFling(0, velocityY);
+ } else {
+ fling(velocityY);
+ }
+ }
+
private void endDrag() {
mIsBeingDragged = false;
@@ -1603,6 +1623,34 @@
}
@Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void onStopNestedScroll(View target) {
+ super.onStopNestedScroll(target);
+ }
+
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed) {
+ scrollBy(0, dyUnconsumed);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY) {
+ flingWithNestedDispatch((int) velocityY);
+ return true;
+ }
+
+ @Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (mEdgeGlowTop != null) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 7640749..4726da7 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -102,7 +102,7 @@
private ScrollView mScrollView;
- private int mIconId = -1;
+ private int mIconId = 0;
private Drawable mIcon;
@@ -337,25 +337,39 @@
}
/**
- * Set resId to 0 if you don't want an icon.
- * @param resId the resourceId of the drawable to use as the icon or 0
- * if you don't want an icon.
+ * Specifies the icon to display next to the alert title.
+ *
+ * @param resId the resource identifier of the drawable to use as the icon,
+ * or 0 for no icon
*/
public void setIcon(int resId) {
+ mIcon = null;
mIconId = resId;
+
if (mIconView != null) {
- if (resId > 0) {
+ if (resId != 0) {
mIconView.setImageResource(mIconId);
- } else if (resId == 0) {
+ } else {
mIconView.setVisibility(View.GONE);
}
}
}
-
+
+ /**
+ * Specifies the icon to display next to the alert title.
+ *
+ * @param icon the drawable to use as the icon or null for no icon
+ */
public void setIcon(Drawable icon) {
mIcon = icon;
- if ((mIconView != null) && (mIcon != null)) {
- mIconView.setImageDrawable(icon);
+ mIconId = 0;
+
+ if (mIconView != null) {
+ if (icon != null) {
+ mIconView.setImageDrawable(icon);
+ } else {
+ mIconView.setVisibility(View.GONE);
+ }
}
}
@@ -485,28 +499,24 @@
View titleTemplate = mWindow.findViewById(R.id.title_template);
titleTemplate.setVisibility(View.GONE);
} else {
- final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
-
mIconView = (ImageView) mWindow.findViewById(R.id.icon);
- if (hasTextTitle) {
- /* Display the title if a title is supplied, else hide it */
- mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
+ final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
+ if (hasTextTitle) {
+ // Display the title if a title is supplied, else hide it.
+ mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
mTitleView.setText(mTitle);
-
- /* Do this last so that if the user has supplied any
- * icons we use them instead of the default ones. If the
- * user has specified 0 then make it disappear.
- */
- if (mIconId > 0) {
+
+ // Do this last so that if the user has supplied any icons we
+ // use them instead of the default ones. If the user has
+ // specified 0 then make it disappear.
+ if (mIconId != 0) {
mIconView.setImageResource(mIconId);
} else if (mIcon != null) {
mIconView.setImageDrawable(mIcon);
- } else if (mIconId == 0) {
-
- /* Apply the padding from the icon to ensure the
- * title is aligned correctly.
- */
+ } else {
+ // Apply the padding from the icon to ensure the title is
+ // aligned correctly.
mTitleView.setPadding(mIconView.getPaddingLeft(),
mIconView.getPaddingTop(),
mIconView.getPaddingRight(),
@@ -514,9 +524,8 @@
mIconView.setVisibility(View.GONE);
}
} else {
-
// Hide the title template
- View titleTemplate = mWindow.findViewById(R.id.title_template);
+ final View titleTemplate = mWindow.findViewById(R.id.title_template);
titleTemplate.setVisibility(View.GONE);
mIconView.setVisibility(View.GONE);
topPanel.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 32f700d..fc89b31 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -19,6 +19,7 @@
import com.android.internal.os.BatteryStatsImpl;
import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.SignalStrength;
interface IBatteryStats {
@@ -55,7 +56,7 @@
void noteScreenOff();
void noteInputEvent();
void noteUserActivity(int uid, int event);
- void noteDataConnectionActive(int type, boolean active, long timestampNs);
+ void noteMobileRadioPowerState(int powerState, long timestampNs);
void notePhoneOn();
void notePhoneOff();
void notePhoneSignalStrength(in SignalStrength signalStrength);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
new file mode 100644
index 0000000..3219ddd
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.internal.app;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.internal.app.IVoiceInteractor;
+import android.service.voice.IVoiceInteractionService;
+import android.service.voice.IVoiceInteractionSession;
+
+interface IVoiceInteractionManagerService {
+ void startVoiceActivity(in Intent intent, String resolvedType, IVoiceInteractionService service,
+ in Bundle sessionArgs);
+ int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+ IVoiceInteractor interactor);
+}
diff --git a/core/java/com/android/internal/app/IVoiceInteractor.aidl b/core/java/com/android/internal/app/IVoiceInteractor.aidl
new file mode 100644
index 0000000..737906a
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractor.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.os.Bundle;
+
+import com.android.internal.app.IVoiceInteractorCallback;
+import com.android.internal.app.IVoiceInteractorRequest;
+
+/**
+ * IPC interface for an application to perform calls through a VoiceInteractor.
+ */
+interface IVoiceInteractor {
+ IVoiceInteractorRequest startConfirmation(String callingPackage,
+ IVoiceInteractorCallback callback, String prompt, in Bundle extras);
+ IVoiceInteractorRequest startCommand(String callingPackage,
+ IVoiceInteractorCallback callback, String command, in Bundle extras);
+ boolean[] supportsCommands(String callingPackage, in String[] commands);
+}
diff --git a/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl
new file mode 100644
index 0000000..c6f93e1
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.internal.app;
+
+import android.os.Bundle;
+
+import com.android.internal.app.IVoiceInteractorRequest;
+
+/**
+ * IPC interface for an application to receive callbacks from the voice system.
+ */
+oneway interface IVoiceInteractorCallback {
+ void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed,
+ in Bundle result);
+ void deliverCommandResult(IVoiceInteractorRequest request, boolean complete, in Bundle result);
+ void deliverCancel(IVoiceInteractorRequest request);
+}
diff --git a/core/java/com/android/internal/app/IVoiceInteractorRequest.aidl b/core/java/com/android/internal/app/IVoiceInteractorRequest.aidl
new file mode 100644
index 0000000..ce2902d
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractorRequest.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.internal.app;
+
+/**
+ * IPC interface identifying a request from an application calling through an IVoiceInteractor.
+ */
+interface IVoiceInteractorRequest {
+ void cancel();
+}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 1bfad05..446ef55 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -26,6 +26,9 @@
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.SELinux;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
import android.util.Log;
import com.android.org.bouncycastle.util.encoders.Base64;
@@ -37,10 +40,7 @@
import java.util.ArrayList;
import java.util.Collections;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.StructStat;
-import static libcore.io.OsConstants.*;
+import static android.system.OsConstants.*;
/**
* Backup transport for stashing stuff into a known location on disk, and
@@ -109,7 +109,7 @@
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
if (DEBUG) {
try {
- StructStat ss = Libcore.os.fstat(data.getFileDescriptor());
+ StructStat ss = Os.fstat(data.getFileDescriptor());
Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName
+ " size=" + ss.st_size);
} catch (ErrnoException e) {
@@ -152,7 +152,7 @@
changeSet.readEntityData(buf, 0, dataSize);
if (DEBUG) {
try {
- long cur = Libcore.os.lseek(data.getFileDescriptor(), 0, SEEK_CUR);
+ long cur = Os.lseek(data.getFileDescriptor(), 0, SEEK_CUR);
Log.v(TAG, " read entity data; new pos=" + cur);
}
catch (ErrnoException e) {
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 1dd1f5e..7ff949e 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -22,6 +22,8 @@
import static android.os.BatteryStats.NETWORK_WIFI_TX_DATA;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.net.ConnectivityManager;
@@ -60,11 +62,14 @@
private static final String TAG = BatteryStatsHelper.class.getSimpleName();
private static BatteryStats sStatsXfer;
+ private static Intent sBatteryBroadcastXfer;
final private Context mContext;
+ final private boolean mCollectBatteryBroadcast;
private IBatteryStats mBatteryInfo;
private BatteryStats mStats;
+ private Intent mBatteryBroadcast;
private PowerProfile mPowerProfile;
private final List<BatterySipper> mUsageList = new ArrayList<BatterySipper>();
@@ -85,6 +90,8 @@
long mBatteryUptime;
long mTypeBatteryRealtime;
long mTypeBatteryUptime;
+ long mBatteryTimeRemaining;
+ long mChargeTimeRemaining;
private long mStatsPeriod = 0;
private double mMaxPower = 1;
@@ -102,7 +109,12 @@
private long mAppWifiRunning;
public BatteryStatsHelper(Context context) {
+ this(context, true);
+ }
+
+ public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) {
mContext = context;
+ mCollectBatteryBroadcast = collectBatteryBroadcast;
}
/** Clears the current stats and forces recreating for future use. */
@@ -117,6 +129,13 @@
return mStats;
}
+ public Intent getBatteryBroadcast() {
+ if (mBatteryBroadcast == null && mCollectBatteryBroadcast) {
+ load();
+ }
+ return mBatteryBroadcast;
+ }
+
public PowerProfile getPowerProfile() {
return mPowerProfile;
}
@@ -129,6 +148,7 @@
public void create(Bundle icicle) {
if (icicle != null) {
mStats = sStatsXfer;
+ mBatteryBroadcast = sBatteryBroadcastXfer;
}
mBatteryInfo = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
@@ -137,6 +157,7 @@
public void storeState() {
sStatsXfer = mStats;
+ sBatteryBroadcastXfer = mBatteryBroadcast;
}
public static String makemAh(double power) {
@@ -190,6 +211,8 @@
mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeUs);
mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
+ mBatteryTimeRemaining = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
+ mChargeTimeRemaining = mStats.computeChargeTimeRemaining(rawRealtimeUs);
if (DEBUG) {
Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs/1000) + " uptime="
@@ -787,6 +810,10 @@
return mMaxDrainedPower;
}
+ public long getBatteryTimeRemaining() { return mBatteryTimeRemaining; }
+
+ public long getChargeTimeRemaining() { return mChargeTimeRemaining; }
+
private void load() {
if (mBatteryInfo == null) {
return;
@@ -803,5 +830,9 @@
} catch (RemoteException e) {
Log.e(TAG, "RemoteException:", e);
}
+ if (mCollectBatteryBroadcast) {
+ mBatteryBroadcast = mContext.registerReceiver(null,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ }
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index eaedba5..343c507 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -38,6 +38,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -87,7 +88,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 101 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 103 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -284,7 +285,7 @@
int mBluetoothState = -1;
final StopwatchTimer[] mBluetoothStateTimer = new StopwatchTimer[NUM_BLUETOOTH_STATES];
- boolean mMobileRadioActive;
+ int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
StopwatchTimer mMobileRadioActiveTimer;
StopwatchTimer mMobileRadioActivePerAppTimer;
LongSamplingCounter mMobileRadioActiveAdjustedTime;
@@ -306,7 +307,9 @@
*/
int mDischargeStartLevel;
int mDischargeUnplugLevel;
+ int mDischargePlugLevel;
int mDischargeCurrentLevel;
+ int mCurrentBatteryLevel;
int mLowDischargeAmountSinceCharge;
int mHighDischargeAmountSinceCharge;
int mDischargeScreenOnUnplugLevel;
@@ -2736,40 +2739,41 @@
}
}
- public void noteDataConnectionActive(int type, boolean active, long timestampNs) {
- if (ConnectivityManager.isNetworkTypeMobile(type)) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
- if (mMobileRadioActive != active) {
- long realElapsedRealtimeMs;
- if (active) {
+ public void noteMobileRadioPowerState(int powerState, long timestampNs) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ if (mMobileRadioPowerState != powerState) {
+ long realElapsedRealtimeMs;
+ final boolean active =
+ powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
+ || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+ if (active) {
+ realElapsedRealtimeMs = elapsedRealtime;
+ mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+ } else {
+ realElapsedRealtimeMs = timestampNs / (1000*1000);
+ long lastUpdateTimeMs = mMobileRadioActiveTimer.getLastUpdateTimeMs();
+ if (realElapsedRealtimeMs < lastUpdateTimeMs) {
+ Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
+ + " is before start time " + lastUpdateTimeMs);
realElapsedRealtimeMs = elapsedRealtime;
- mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
- } else {
- realElapsedRealtimeMs = timestampNs / (1000*1000);
- long lastUpdateTimeMs = mMobileRadioActiveTimer.getLastUpdateTimeMs();
- if (realElapsedRealtimeMs < lastUpdateTimeMs) {
- Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
- + " is before start time " + lastUpdateTimeMs);
- realElapsedRealtimeMs = elapsedRealtime;
- } else if (realElapsedRealtimeMs < elapsedRealtime) {
- mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtime
- - realElapsedRealtimeMs);
- }
- mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+ } else if (realElapsedRealtimeMs < elapsedRealtime) {
+ mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtime
+ - realElapsedRealtimeMs);
}
- if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
- + Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(elapsedRealtime, uptime);
- mMobileRadioActive = active;
- if (active) {
- mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
- mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
- } else {
- mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
- updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
- mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
- }
+ mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+ }
+ if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mMobileRadioPowerState = powerState;
+ if (active) {
+ mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
+ mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
+ } else {
+ mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
+ updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
+ mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
}
}
}
@@ -5520,7 +5524,9 @@
initTimes(uptime, realtime);
mDischargeStartLevel = 0;
mDischargeUnplugLevel = 0;
+ mDischargePlugLevel = -1;
mDischargeCurrentLevel = 0;
+ mCurrentBatteryLevel = 0;
initDischarge();
clearHistoryLocked();
}
@@ -5726,7 +5732,8 @@
mDischargeStartLevel = mHistoryCur.batteryLevel;
pullPendingStateUpdatesLocked();
addHistoryRecordLocked(mSecRealtime, mSecUptime);
- mDischargeCurrentLevel = mDischargeUnplugLevel = mHistoryCur.batteryLevel;
+ mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel
+ = mCurrentBatteryLevel = mHistoryCur.batteryLevel;
mOnBatteryTimeBase.reset(uptime, realtime);
mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
@@ -5907,7 +5914,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(mSecRealtime, mSecUptime);
- mDischargeCurrentLevel = level;
+ mDischargeCurrentLevel = mDischargePlugLevel = level;
if (level < mDischargeUnplugLevel) {
mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
@@ -5971,6 +5978,10 @@
startRecordingHistory(elapsedRealtime, uptime, true);
}
}
+ mCurrentBatteryLevel = level;
+ if (mDischargePlugLevel < 0) {
+ mDischargePlugLevel = level;
+ }
if (onBattery != mOnBattery) {
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.batteryStatus = (byte)status;
@@ -6224,6 +6235,42 @@
return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which);
}
+ @Override
+ public long computeBatteryTimeRemaining(long curTime) {
+ if (!mOnBattery) {
+ return -1;
+ }
+ int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2;
+ if (discharge < 2) {
+ return -1;
+ }
+ long duration = computeBatteryRealtime(curTime, STATS_SINCE_CHARGED);
+ if (duration < 1000*1000) {
+ return -1;
+ }
+ long usPerLevel = duration/discharge;
+ return usPerLevel * mCurrentBatteryLevel;
+ }
+
+ @Override
+ public long computeChargeTimeRemaining(long curTime) {
+ if (true || mOnBattery) {
+ // Not yet working.
+ return -1;
+ }
+ int curLevel = mCurrentBatteryLevel;
+ int plugLevel = mDischargePlugLevel;
+ if (plugLevel < 0 || curLevel < (plugLevel+1)) {
+ return -1;
+ }
+ long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
+ if (duration < 1000*1000) {
+ return -1;
+ }
+ long usPerLevel = duration/(curLevel-plugLevel);
+ return usPerLevel * (100-curLevel);
+ }
+
long getBatteryUptimeLocked() {
return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
}
@@ -6722,7 +6769,9 @@
mOnBatteryTimeBase.readSummaryFromParcel(in);
mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
mDischargeUnplugLevel = in.readInt();
+ mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
+ mCurrentBatteryLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
@@ -6749,7 +6798,7 @@
mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
- mMobileRadioActive = false;
+ mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
@@ -6974,7 +7023,9 @@
mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
out.writeInt(mDischargeUnplugLevel);
+ out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
+ out.writeInt(mCurrentBatteryLevel);
out.writeInt(getLowDischargeAmountSinceCharge());
out.writeInt(getHighDischargeAmountSinceCharge());
out.writeInt(getDischargeAmountScreenOnSinceCharge());
@@ -7262,7 +7313,7 @@
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
- mMobileRadioActive = false;
+ mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase, in);
mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase,
in);
@@ -7284,7 +7335,9 @@
null, mOnBatteryTimeBase, in);
}
mDischargeUnplugLevel = in.readInt();
+ mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
+ mCurrentBatteryLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOn = in.readInt();
@@ -7402,7 +7455,9 @@
mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
}
out.writeInt(mDischargeUnplugLevel);
+ out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
+ out.writeInt(mCurrentBatteryLevel);
out.writeInt(mLowDischargeAmountSinceCharge);
out.writeInt(mHighDischargeAmountSinceCharge);
out.writeInt(mDischargeAmountScreenOn);
@@ -7499,6 +7554,7 @@
pr.println("*** Data connection type #" + i + ":");
mPhoneDataConnectionsTimer[i].logState(pr, " ");
}
+ pr.println("*** mMobileRadioPowerState=" + mMobileRadioPowerState);
pr.println("*** Mobile network active timer:");
mMobileRadioActiveTimer.logState(pr, " ");
pr.println("*** Mobile network active adjusted timer:");
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index d9e3ef6..40834ba 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -85,7 +85,27 @@
public void sendMessage(Message msg) {
mH.sendMessage(msg);
}
-
+
+ public SomeArgs sendMessageAndWait(Message msg) {
+ if (Looper.myLooper() == mH.getLooper()) {
+ throw new IllegalStateException("Can't wait on same thread as looper");
+ }
+ SomeArgs args = (SomeArgs)msg.obj;
+ args.mWaitState = SomeArgs.WAIT_WAITING;
+ mH.sendMessage(msg);
+ synchronized (args) {
+ while (args.mWaitState == SomeArgs.WAIT_WAITING) {
+ try {
+ args.wait();
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+ }
+ args.mWaitState = SomeArgs.WAIT_NONE;
+ return args;
+ }
+
public Message obtainMessage(int what) {
return mH.obtainMessage(what);
}
@@ -136,6 +156,14 @@
return mH.obtainMessage(what, arg1, 0, args);
}
+ public Message obtainMessageIOOO(int what, int arg1, Object arg2, Object arg3, Object arg4) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = arg2;
+ args.arg2 = arg3;
+ args.arg3 = arg4;
+ return mH.obtainMessage(what, arg1, 0, args);
+ }
+
public Message obtainMessageOO(int what, Object arg1, Object arg2) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = arg1;
@@ -161,6 +189,17 @@
return mH.obtainMessage(what, 0, 0, args);
}
+ public Message obtainMessageOOOOO(int what, Object arg1, Object arg2,
+ Object arg3, Object arg4, Object arg5) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = arg1;
+ args.arg2 = arg2;
+ args.arg3 = arg3;
+ args.arg4 = arg4;
+ args.arg5 = arg5;
+ return mH.obtainMessage(what, 0, 0, args);
+ }
+
public Message obtainMessageIIII(int what, int arg1, int arg2,
int arg3, int arg4) {
SomeArgs args = SomeArgs.obtain();
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index 6fb72f1..7edf4cc 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -35,6 +35,11 @@
private boolean mInPool;
+ static final int WAIT_NONE = 0;
+ static final int WAIT_WAITING = 1;
+ static final int WAIT_FINISHED = 2;
+ int mWaitState = WAIT_NONE;
+
public Object arg1;
public Object arg2;
public Object arg3;
@@ -70,6 +75,9 @@
if (mInPool) {
throw new IllegalStateException("Already recycled.");
}
+ if (mWaitState != WAIT_NONE) {
+ return;
+ }
synchronized (sPoolLock) {
clear();
if (sPoolSize < MAX_POOL_SIZE) {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index c5fa0a1..54c532a 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -18,8 +18,8 @@
import dalvik.system.ZygoteHooks;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
+import android.system.ErrnoException;
+import android.system.Os;
/** @hide */
public final class Zygote {
@@ -141,7 +141,7 @@
public static void execShell(String command) {
String[] args = { "/system/bin/sh", "-c", command };
try {
- Libcore.os.execv(args[0], args);
+ Os.execv(args[0], args);
} catch (ErrnoException e) {
throw new RuntimeException(e);
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 58a8e62..0c48368 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -21,6 +21,8 @@
import android.os.Process;
import android.os.SELinux;
import android.os.SystemProperties;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
import dalvik.system.PathClassLoader;
import java.io.BufferedReader;
@@ -34,9 +36,7 @@
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
/**
* A connection that can make spawn requests.
@@ -186,7 +186,7 @@
}
if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
- FileDescriptor[] pipeFds = Libcore.os.pipe();
+ FileDescriptor[] pipeFds = Os.pipe();
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
ZygoteInit.setCloseOnExec(serverPipeFd, true);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ef2908d..3ea749e 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -16,8 +16,8 @@
package com.android.internal.os;
-import static libcore.io.OsConstants.S_IRWXG;
-import static libcore.io.OsConstants.S_IRWXO;
+import static android.system.OsConstants.S_IRWXG;
+import static android.system.OsConstants.S_IRWXO;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -28,14 +28,15 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.EventLog;
import android.util.Log;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.OsConstants;
import java.io.BufferedReader;
import java.io.FileDescriptor;
@@ -195,12 +196,12 @@
FileDescriptor fd = sServerSocket.getFileDescriptor();
sServerSocket.close();
if (fd != null) {
- Libcore.os.close(fd);
+ Os.close(fd);
}
}
} catch (IOException ex) {
Log.e(TAG, "Zygote: error closing sockets", ex);
- } catch (libcore.io.ErrnoException ex) {
+ } catch (ErrnoException ex) {
Log.e(TAG, "Zygote: error closing descriptor", ex);
}
@@ -481,7 +482,7 @@
closeServerSocket();
// set umask to 0077 so new files and directories will default to owner-only permissions.
- Libcore.os.umask(S_IRWXG | S_IRWXO);
+ Os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
diff --git a/core/java/com/android/server/SystemService.java b/core/java/com/android/server/SystemService.java
index e374563..bf36bb1 100644
--- a/core/java/com/android/server/SystemService.java
+++ b/core/java/com/android/server/SystemService.java
@@ -123,6 +123,38 @@
public void onBootPhase(int phase) {}
/**
+ * Called when a new user is starting, for system services to initialize any per-user
+ * state they maintain for running users.
+ * @param userHandle The identifier of the user.
+ */
+ public void onStartUser(int userHandle) {}
+
+ /**
+ * Called when switching to a different foreground user, for system services that have
+ * special behavior for whichever user is currently in the foreground. This is called
+ * before any application processes are aware of the new user.
+ * @param userHandle The identifier of the user.
+ */
+ public void onSwitchUser(int userHandle) {}
+
+ /**
+ * Called when an existing user is stopping, for system services to finalize any per-user
+ * state they maintain for running users. This is called prior to sending the SHUTDOWN
+ * broadcast to the user; it is a good place to stop making use of any resources of that
+ * user (such as binding to a service running in the user).
+ * @param userHandle The identifier of the user.
+ */
+ public void onStopUser(int userHandle) {}
+
+ /**
+ * Called when an existing user is stopping, for system services to finalize any per-user
+ * state they maintain for running users. This is called after all application process
+ * teardown of the user is complete.
+ * @param userHandle The identifier of the user.
+ */
+ public void onCleanupUser(int userHandle) {}
+
+ /**
* Publish the service so it is accessible to other services and apps.
*/
protected final void publishBinderService(String name, IBinder service) {
diff --git a/core/java/com/android/server/SystemServiceManager.java b/core/java/com/android/server/SystemServiceManager.java
index eb8df0e..87a50a9 100644
--- a/core/java/com/android/server/SystemServiceManager.java
+++ b/core/java/com/android/server/SystemServiceManager.java
@@ -131,6 +131,58 @@
}
}
+ public void startUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onStartUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting start of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void switchUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onSwitchUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting switch of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void stopUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onStopUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting stop of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void cleanupUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onCleanupUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
/** Sets the safe mode flag for services to query. */
public void setSafeMode(boolean safeMode) {
mSafeMode = safeMode;
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 5148266..2adbf3a 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -509,12 +509,11 @@
}
static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle,
- jobject jrect, jfloat rx, jfloat ry,
- jlong paintHandle) {
+ jfloat left, jfloat top, jfloat right, jfloat bottom, jfloat rx, jfloat ry,
+ jlong paintHandle) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
- SkRect rect;
- GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
canvas->drawRoundRect(rect, rx, ry, *paint);
}
@@ -1176,7 +1175,7 @@
{"native_drawCircle","(JFFFJ)V", (void*) SkCanvasGlue::drawCircle},
{"native_drawArc","(JLandroid/graphics/RectF;FFZJ)V",
(void*) SkCanvasGlue::drawArc},
- {"native_drawRoundRect","(JLandroid/graphics/RectF;FFJ)V",
+ {"native_drawRoundRect","(JFFFFFFJ)V",
(void*) SkCanvasGlue::drawRoundRect},
{"native_drawPath","(JJJ)V", (void*) SkCanvasGlue::drawPath},
{"native_drawBitmap","(JJFFJIII)V",
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 1ad1a8a..420a17f 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -163,42 +163,35 @@
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->close();
}
-
- static void addRect__RectFI(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect, jint dirHandle) {
- SkRect rect;
- SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
- GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
- obj->addRect(rect, dir);
- }
-
- static void addRect__FFFFI(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
+
+ static void addRect(JNIEnv* env, jobject clazz, jlong objHandle,
+ jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
obj->addRect(left, top, right, bottom, dir);
}
-
- static void addOval(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jint dirHandle) {
+
+ static void addOval(JNIEnv* env, jobject clazz, jlong objHandle,
+ jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
- SkRect oval_;
- GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
- obj->addOval(oval_, dir);
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
+ obj->addOval(oval, dir);
}
-
+
static void addCircle(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y, jfloat radius, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
obj->addCircle(x, y, radius, dir);
}
-
+
static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle) {
SkRect oval_;
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
obj->addArc(oval_, startAngle, sweepAngle);
}
-
+
static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect,
jfloat rx, jfloat ry, jint dirHandle) {
SkRect rect;
@@ -496,9 +489,8 @@
{"native_rCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo},
{"native_arcTo","(JLandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo},
{"native_close","(J)V", (void*) SkPathGlue::close},
- {"native_addRect","(JLandroid/graphics/RectF;I)V", (void*) SkPathGlue::addRect__RectFI},
- {"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect__FFFFI},
- {"native_addOval","(JLandroid/graphics/RectF;I)V", (void*) SkPathGlue::addOval},
+ {"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect},
+ {"native_addOval","(JFFFFI)V", (void*) SkPathGlue::addOval},
{"native_addCircle","(JFFFI)V", (void*) SkPathGlue::addCircle},
{"native_addArc","(JLandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc},
{"native_addRoundRect","(JLandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY},
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 7a4728d..fcf8f83e 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -160,7 +160,6 @@
ASensorEvent buffer[16];
while ((n = q->read(buffer, 16)) > 0) {
for (int i=0 ; i<n ; i++) {
-
if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
// step-counter returns a uint64, but the java API only deals with floats
float value = float(buffer[i].u64.step_counter);
@@ -183,17 +182,17 @@
buffer[i].vector.status,
buffer[i].timestamp);
}
-
if (env->ExceptionCheck()) {
+ mSensorQueue->sendAck(buffer, n);
ALOGE("Exception dispatching input event.");
return 1;
}
}
+ mSensorQueue->sendAck(buffer, n);
}
if (n<0 && n != -EAGAIN) {
// FIXME: error receiving events, what to do in this case?
}
-
return 1;
}
};
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index a4efed7..01f4d3a 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -30,15 +30,16 @@
#include "android_util_Binder.h"
#include "JNIHelp.h"
-#include <sys/errno.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <grp.h>
+#include <inttypes.h>
#include <pwd.h>
#include <signal.h>
+#include <sys/errno.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#define POLICY_DEBUG 0
@@ -159,7 +160,7 @@
void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int tid, jint grp)
{
- ALOGV("%s tid=%d grp=%d", __func__, tid, grp);
+ ALOGV("%s tid=%d grp=%" PRId32, __func__, tid, grp);
SchedPolicy sp = (SchedPolicy) grp;
int res = set_sched_policy(tid, sp);
if (res != NO_ERROR) {
@@ -169,7 +170,7 @@
void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
{
- ALOGV("%s pid=%d grp=%d", __func__, pid, grp);
+ ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
DIR *d;
FILE *fp;
char proc_path[255];
@@ -322,7 +323,7 @@
}
}
- //ALOGI("Setting priority of %d: %d, getpriority returns %d\n",
+ //ALOGI("Setting priority of %" PRId32 ": %" PRId32 ", getpriority returns %d\n",
// pid, pri, getpriority(PRIO_PROCESS, pid));
}
@@ -340,7 +341,7 @@
if (errno != 0) {
signalExceptionForPriorityError(env, errno);
}
- //ALOGI("Returning priority of %d: %d\n", pid, pri);
+ //ALOGI("Returning priority of %" PRId32 ": %" PRId32 "\n", pid, pri);
return pri;
}
@@ -362,7 +363,7 @@
int fd = open(text, O_WRONLY);
if (fd >= 0) {
- sprintf(text, "%d", pid);
+ sprintf(text, "%" PRId32, pid);
write(fd, text, strlen(text));
close(fd);
}
@@ -403,7 +404,7 @@
static int pid_compare(const void* v1, const void* v2)
{
- //ALOGI("Compare %d vs %d\n", *((const jint*)v1), *((const jint*)v2));
+ //ALOGI("Compare %" PRId32 " vs %" PRId32 "\n", *((const jint*)v1), *((const jint*)v2));
return *((const jint*)v1) - *((const jint*)v2);
}
@@ -517,7 +518,7 @@
return;
}
- //ALOGI("Clearing %d sizes", count);
+ //ALOGI("Clearing %" PRId32 " sizes", count);
for (i=0; i<count; i++) {
sizesArray[i] = 0;
}
@@ -556,7 +557,7 @@
}
char* end;
sizesArray[i] = strtoll(num, &end, 10);
- //ALOGI("Field %s = %d", field.string(), sizesArray[i]);
+ //ALOGI("Field %s = %" PRId64, field.string(), sizesArray[i]);
foundCount++;
break;
}
@@ -758,7 +759,7 @@
}
}
- //ALOGI("Field %d: %d-%d dest=%d mode=0x%x\n", i, start, end, di, mode);
+ //ALOGI("Field %" PRId32 ": %" PRId32 "-%" PRId32 " dest=%" PRId32 " mode=0x%" PRIx32 "\n", i, start, end, di, mode);
if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) {
char c = buffer[end];
@@ -857,7 +858,7 @@
void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig)
{
if (pid > 0) {
- ALOGI("Sending signal. PID: %d SIG: %d", pid, sig);
+ ALOGI("Sending signal. PID: %" PRId32 " SIG: %" PRId32, pid, sig);
kill(pid, sig);
}
}
@@ -887,7 +888,7 @@
{
char filename[64];
- snprintf(filename, sizeof(filename), "/proc/%d/smaps", pid);
+ snprintf(filename, sizeof(filename), "/proc/%" PRId32 "/smaps", pid);
FILE * file = fopen(filename, "r");
if (!file) {
@@ -899,7 +900,7 @@
jlong pss = 0;
while (fgets(line, sizeof(line), file)) {
jlong v;
- if (sscanf(line, "Pss: %lld kB", &v) == 1) {
+ if (sscanf(line, "Pss: %" SCNd64 " kB", &v) == 1) {
pss += v;
}
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 8549004..ef5ebd0 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -287,7 +287,7 @@
jlong rendererPtr, jlong paintPtr, jint saveFlags) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
- const android::uirenderer::Rect& bounds(renderer->getClipBounds());
+ const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
return renderer->saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
paint, saveFlags);
}
@@ -302,7 +302,7 @@
static jint android_view_GLES20Canvas_saveLayerAlphaClip(JNIEnv* env, jobject clazz,
jlong rendererPtr, jint alpha, jint saveFlags) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- const android::uirenderer::Rect& bounds(renderer->getClipBounds());
+ const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
return renderer->saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
alpha, saveFlags);
}
@@ -356,7 +356,7 @@
static jboolean android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject clazz,
jlong rendererPtr, jobject rect) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- const android::uirenderer::Rect& bounds(renderer->getClipBounds());
+ const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
env->CallVoidMethod(rect, gRectClassInfo.set,
int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
@@ -870,8 +870,7 @@
return reinterpret_cast<jlong>(renderer->finishRecording());
}
-static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
- jobject clazz) {
+static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) {
return reinterpret_cast<jlong>(new DisplayListRenderer);
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 8dacfeb..3ad2ae5 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -164,6 +164,12 @@
renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering);
}
+static void android_view_RenderNode_setElevation(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, float elevation) {
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ renderNode->mutateStagingProperties().setElevation(elevation);
+}
+
static void android_view_RenderNode_setTranslationX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float tx) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -331,6 +337,12 @@
return renderNode->stagingProperties().getScaleY();
}
+static jfloat android_view_RenderNode_getElevation(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr) {
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ return renderNode->stagingProperties().getElevation();
+}
+
static jfloat android_view_RenderNode_getTranslationX(JNIEnv* env,
jobject clazz, jlong renderNodePtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -457,6 +469,7 @@
{ "nSetAlpha", "(JF)V", (void*) android_view_RenderNode_setAlpha },
{ "nSetHasOverlappingRendering", "(JZ)V",
(void*) android_view_RenderNode_setHasOverlappingRendering },
+ { "nSetElevation", "(JF)V", (void*) android_view_RenderNode_setElevation },
{ "nSetTranslationX", "(JF)V", (void*) android_view_RenderNode_setTranslationX },
{ "nSetTranslationY", "(JF)V", (void*) android_view_RenderNode_setTranslationY },
{ "nSetTranslationZ", "(JF)V", (void*) android_view_RenderNode_setTranslationZ },
@@ -485,6 +498,7 @@
{ "nGetCameraDistance", "(J)F", (void*) android_view_RenderNode_getCameraDistance },
{ "nGetScaleX", "(J)F", (void*) android_view_RenderNode_getScaleX },
{ "nGetScaleY", "(J)F", (void*) android_view_RenderNode_getScaleY },
+ { "nGetElevation", "(J)F", (void*) android_view_RenderNode_getElevation },
{ "nGetTranslationX", "(J)F", (void*) android_view_RenderNode_getTranslationX },
{ "nGetTranslationY", "(J)F", (void*) android_view_RenderNode_getTranslationY },
{ "nGetTranslationZ", "(J)F", (void*) android_view_RenderNode_getTranslationZ },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8141a00..c293c7a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -508,7 +508,7 @@
nsecs_t presentedTimesNanoSrc[frameCount];
for (size_t i = 0; i < frameCount; i++) {
- nsecs_t presentedTimeNano = stats.desiredPresentTimesNano[i];
+ nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
if (presentedTimeNano == INT64_MAX) {
presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 57e845f..4f093a8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2056,6 +2056,13 @@
android:description="@string/permdesc_bindWallpaper"
android:protectionLevel="signature|system" />
+ <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
+ to ensure that only the system can bind to it. -->
+ <permission android:name="android.permission.BIND_VOICE_INTERACTION"
+ android:label="@string/permlab_bindVoiceInteraction"
+ android:description="@string/permdesc_bindVoiceInteraction"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
to ensure that only the system can bind to it.
@hide -->
@@ -2620,6 +2627,15 @@
android:description="@string/permdesc_bindNotificationListenerService"
android:protectionLevel="signature" />
+ <!-- Must be required by an {@link
+ android.service.notification.ConditionProviderService},
+ to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_CONDITION_PROVIDER_SERVICE"
+ android:label="@string/permlab_bindConditionProviderService"
+ android:description="@string/permdesc_bindConditionProviderService"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to call into a carrier setup flow. It is up to the
carrier setup application to enforce that this permission is required
@hide This is not a third-party API (intended for OEMs and system apps). -->
diff --git a/core/res/res/drawable/btn_borderless_quantum.xml b/core/res/res/drawable/btn_borderless_quantum.xml
index 69a891a..2e3c515 100644
--- a/core/res/res/drawable/btn_borderless_quantum.xml
+++ b/core/res/res/drawable/btn_borderless_quantum.xml
@@ -16,7 +16,6 @@
<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="?attr/colorButtonPressed">
- <item android:drawable="@color/transparent" />
<item android:id="@id/mask"
android:drawable="@drawable/btn_qntm_alpha" />
</touch-feedback>
diff --git a/core/res/res/drawable/dialog_background_quantum.xml b/core/res/res/drawable/dialog_background_quantum.xml
new file mode 100644
index 0000000..7e5b003
--- /dev/null
+++ b/core/res/res/drawable/dialog_background_quantum.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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+
+ <corners
+ android:radius="2dp" />
+ <solid
+ android:color="?attr/colorBackground" />
+
+</shape>
diff --git a/core/res/res/drawable/list_selector_quantum.xml b/core/res/res/drawable/list_selector_quantum.xml
new file mode 100644
index 0000000..c007117
--- /dev/null
+++ b/core/res/res/drawable/list_selector_quantum.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
+ android:tint="?attr/colorButtonPressed">
+ <item android:id="@id/mask">
+ <color android:color="@color/white" />
+ </item>
+</touch-feedback>
diff --git a/core/res/res/layout/alert_dialog_quantum.xml b/core/res/res/layout/alert_dialog_quantum.xml
index 537162a..80e34cb 100644
--- a/core/res/res/layout/alert_dialog_quantum.xml
+++ b/core/res/res/layout/alert_dialog_quantum.xml
@@ -20,7 +20,10 @@
android:id="@+id/parentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:background="@drawable/dialog_background_quantum"
+ android:translationZ="@dimen/floating_window_z"
+ android:layout_margin="@dimen/floating_window_margin">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/simple_list_item_2_single_choice.xml b/core/res/res/layout/simple_list_item_2_single_choice.xml
index 65c5856..940c6b8 100644
--- a/core/res/res/layout/simple_list_item_2_single_choice.xml
+++ b/core/res/res/layout/simple_list_item_2_single_choice.xml
@@ -21,7 +21,8 @@
android:gravity="center_vertical"
android:paddingStart="16dip"
android:paddingEnd="12dip"
- android:minHeight="?android:attr/listPreferredItemHeightSmall">
+ android:minHeight="?attr/listPreferredItemHeightSmall"
+ android:background="@color/transparent">
<LinearLayout
android:layout_width="wrap_content"
@@ -33,8 +34,8 @@
<TextView android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceListItem"
- android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:textAppearance="?attr/textAppearanceListItem"
+ android:textColor="?attr/textColorAlertDialogListItem"
android:gravity="center_vertical|start"
android:singleLine="true"
android:ellipsize="marquee" />
@@ -42,8 +43,8 @@
<TextView android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceListItemSecondary"
- android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:textAppearance="?attr/textAppearanceListItemSecondary"
+ android:textColor="?attr/textColorAlertDialogListItem"
android:gravity="center_vertical|start"
android:singleLine="true"
android:ellipsize="marquee" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 2988f06..db4092e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegtuigmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegtuigmodus is AAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegtuigmodus is AF"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Instellings"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a32c834..de89ec6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"የአውሮፕላን ሁነታ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"የአውሮፕላንሁነታ በርቷል"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"የአውሮፕላንሁነታ ጠፍቷል"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
@@ -644,7 +646,7 @@
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"መተግበሪያው ስልኩን ከWiMAX አውታረ መረብ ጋር እንዲያገናኝና እንዲያለያይ ይፈቅድለታል።"</string>
<string name="permlab_scoreNetworks" msgid="6445777779383587181">"ለአውታረ መረቦች ነጥብ ይሰጣል"</string>
<string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ጡባዊው የትኛዎቹን አውታረ መረቦች እንደሚመርጥ ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ስልኩ የትኛዎቹን አውታረ መረቦች እንደሚመርጥ ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ስልኩ የትኛዎቹን አውታረ መረቦች እንደሚመርጥ እና ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ከብሉቱዝ መሣሪያዎች ጋር ተጣመር"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"መተግበሪያው በጡባዊ ተኮው ላይ ያለውን የብሉቱዝ ውቅር እንዲያይ እና ከተጣመሩ መሳሪያዎች ጋር ግንኙነቶችን እንዲያደርግና እንዲቀበል ይፈቅድለታል።"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"መተግበሪያው በስልኩ ላይ ያለውን የብሉቱዝ ውቅር እንዲያይ እና ከተጣመሩ መሳሪያዎች ጋር ግንኙነቶችን እንዲያደርግና እንዲቀበል ይፈቅድለታል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 86d2be3..2ee49bd 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"وضع الطائرة"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"وضع الطائرة قيد التشغيل"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"وضع الطائرة متوقف"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"الإعدادات"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"نظام Android"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index fcf3e1b..3f00f1f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Самолетен режим"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Самолетният режим е ВКЛЮЧЕН"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Самолетният режим е ИЗКЛЮЧЕН"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index b422a6d..afb0852 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode d\'avió"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode d\'avió activat"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode d\'avió desactivat"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Configuració"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 416eca9..39c6c08 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V letadle"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V letadle je ZAPNUTÝ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V letadle je VYPNUTÝ"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 7e08df5..c06ecbb 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flytilstand"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flytilstand er TIL"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flytilstand er slået FRA"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Indstillinger"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 162d0d8..e1ee025 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flugmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Einstellungen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
@@ -316,13 +317,13 @@
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"Bildschirminhalt abrufen"</string>
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ermöglicht der App, den Inhalt des aktiven Fensters abzurufen. Schädliche Apps können so den gesamten Fensterinhalt abrufen und mit Ausnahme von Passwörtern den gesamten Text auswerten."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Bedienungshilfen vorübergehend aktivieren"</string>
- <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ermöglicht einer App, die Bedienungshilfen auf dem Gerät vorübergehend zu aktivieren. Schädliche Apps können Bedienungshilfen ohne die Zustimmung des Nutzers aktivieren."</string>
+ <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ermöglicht der App, die Bedienungshilfen auf dem Gerät vorübergehend zu aktivieren. Schädliche Apps können Bedienungshilfen ohne die Zustimmung des Nutzers aktivieren."</string>
<string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"Fenstertoken abrufen"</string>
<string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Berechtigt eine App zum Abruf des Fenstertokens. Bösartige Apps können sich als System ausgeben und unautorisiert mit dem App-Fenster interagieren."</string>
<string name="permlab_frameStats" msgid="7056374987314361639">"Framestatistiken abrufen"</string>
<string name="permdesc_frameStats" msgid="4758001089491284919">"Berechtigt eine App zur Erfassung von Framestatistiken. Bösartige Apps können möglicherweise die Framestatistiken für Fenster von anderen Apps beobachten."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"Ereignisse filtern"</string>
- <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht einer App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
+ <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht der App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"Partielles Herunterfahren"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"App-Wechsel verhindern"</string>
@@ -338,7 +339,7 @@
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Von WAP-PUSH empfangenen Broadcast senden"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Apps können so den Empfang von MMS vortäuschen oder unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte ersetzen."</string>
<string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"Netzwerkbewertungen senden"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ermöglicht der App, Benachrichtigungen zu senden, dass Netzwerke bewertet werden müssen. Für normale Apps sollte dies nie erforderlich sein."</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ermöglicht der App, Benachrichtigungen zu senden, dass Netzwerke bewertet werden müssen. Für normale Apps ist dies nie erforderlich."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"Anzahl der laufenden Prozesse beschränken"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ermöglicht der App, die maximale Anzahl an aktiven Prozessen zu steuern. Wird nie für normale Apps benötigt."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"Apps im Hintergrund schließen"</string>
@@ -1333,7 +1334,7 @@
<string name="permlab_copyProtectedData" msgid="4341036311211406692">"Inhalte kopieren"</string>
<string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ermöglicht der App das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalten. Nicht für normale Apps vorgesehen."</string>
<string name="permlab_route_media_output" msgid="1642024455750414694">"Medienausgabe umleiten"</string>
- <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht einer App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht der App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
<string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Zugriff auf mit Keyguard geschützten Speicher"</string>
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ermöglicht einer App den Zugriff auf mit Keyguard geschützten Speicher"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Anzeige und Ausblenden des Keyguard steuern"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6f013b2..5af0277 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Λειτουργία πτήσης"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Η λειτουργία πτήσης είναι ενεργοποιημένη."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Λειτ. πτήσης είναι ανενεργή"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Ρυθμίσεις"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
<string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9e94287..ad45887 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 9e94287..ad45887 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 337ab64..6d032ca 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 920bdbc..63bed24 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avión activado. Desactivar"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avión desactivado. Activar"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Ajustes"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"> 999"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 222a06c..00e4a20 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lennurežiim"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lennurežiim on SEES"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lennurežiim on VÄLJAS"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 300dfcd..42d654e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"حالت هواپیما"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"حالت هواپیما روشن است"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"حالت هواپیما خاموش است"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
<string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"سیستم Android"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9202e0d..7698dda 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lentokonetila"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lentokonetila on KÄYTÖSSÄ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lentokonetila on POIS KÄYTÖSTÄ"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
@@ -390,10 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Antaa sovelluksen sitoutua etänäytön ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sitoudu widget-palveluun"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
- <!-- no translation found for permlab_bindRouteProvider (4869394607915096847) -->
- <skip />
- <!-- no translation found for permdesc_bindRouteProvider (4703804520859960329) -->
- <skip />
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"reitin tarjoajan palveluun sitominen"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Antaa sovelluksen luoda sidoksen mihin tahansa rekisteröityyn reitin tarjoajaan. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Antaa sovelluksen lähettää aikomuksia laitteen järjestelmänvalvojalle. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"sido TV-tuloon"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 5e2cb28..cc3bcd2 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 6435652..30c7767 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 831b327..852215f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"हवाई जहाज मोड"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"हवाई जहाज मोड चालू है"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"हवाई जहाज मोड बंद है"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"सेटिंग"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 40b194c..4ab25af 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -135,7 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkronizacija"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše brisanja stavki <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Prostor za pohranu tabletnog računala pun je. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Pohrana sata puna je. Izbrišite neke datoteke da biste oslobodili prostor."</string>
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Memorija sata je puna. Izbrišite neke datoteke da biste oslobodili prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Prostor za pohranu na telefonu je pun. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadzire"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način rada u zrakoplovu"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uključen je način rada u zrakoplovu"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Isključen je način rada u zrakoplovu"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 7c95b53..cc47d26 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Repülőgép üzemmód"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Repülőgép üzemmód bekapcsolva"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Repülőgép üzemmód kikapcsolva"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Beállítások"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index c788068..34bebb2 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռային ռեժիմ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռային ռեժիմը միացված է"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռային ռեժիմը անջատված է"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index a7ede78..1100bd0 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode pesawat"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode pesawat AKTIF"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode pesawat MATI"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Setelan"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 4c3d8a3..243dd15 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modalità aereo"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modalità aereo attiva"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modalità aereo non attiva"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Impostazioni"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f818574..537aac6 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"מצב טיסה"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"מצב טיסה מופעל"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"מצב טיסה כבוי"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"הגדרות"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
<string name="android_system_label" msgid="6577375335728551336">"מערכת Android"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 159a19e..e334773 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"機内モード"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
<string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index db9088c..b6856c6 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"თვითმფრინავის რეჟიმი"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"თვითმფრინავის რეჟიმი ჩართულია."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"თვითმფრინავის რეჟიმი გამორთულია."</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 7eb674a..bac95d577 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ពេលជិះយន្តហោះ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"បានបើករបៀបពេលជិះយន្តហោះ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"បានបិទរបៀបពេលជិះយន្តហោះ"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"ការកំណត់"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
<string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ Android"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f73469a..7b064a3 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"비행기 모드"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"비행기 모드 사용중"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"비행기 모드 사용중이 아님"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 80964b6..d486092 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ໂໝດໃນຍົນ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ເປີດໂໝດຢູ່ໃນຍົນແລ້ວ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ປິດໂໝດໃນຍົນແລ້ວ"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
@@ -337,8 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ອະນຸຍາດໃຫ້ແອັບຯ ກະຈາຍສັນຍານການແຈ້ງເຕືອນວ່າຂໍ້ຄວາມ SMS ໄດ້ຮັບແລ້ວ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດຈະໃຊ້ສິ່ງນີ້ໃນການປອມແປງຂໍ້ຄວາມ SMS ຂາເຂົ້າ."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ສົ່ງການກະຈາຍ WAP-PUSH ທີ່ໄດ້ຮັບ"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ອະນຸຍາດໃຫ້ແອັບຯສົ່ງການແຈ້ງເຕືອນໃນເວລາທີ່ໄດ້ຮັບຂໍ້ມຄວາມ WAP PUSH. ແອັບຯທີ່ເປັນອັນຕະລາຍ ອາດໃຊ້ການກະທຳນີ້ເພື່ອປອມການໄດ້ຮັບຂໍ້ຄວາມ MMS ຫຼືລັກປ່ຽນເນື້ອຫາຂອງໜ້າເວັບຕ່າງໆ ດ້ວຍສິ່ງອັນຕະລາຍທັງຫຼາຍຢ່າງງຽບໆ."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ສົ່ງການກະຈາຍເຄືອຂ່າຍຄະແນນ"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ອະນຸຍາດໃຫ້ແອັບຯກະຈາຍການແຈ້ງເຕືອນທີ່ເຄືອຂ່າຍຈຳເປັນໃຊ້ນັບຄະແນນ. ບໍ່ເຄີຍໄດ້ໃຊ້ໃນແອັບຯທົ່ວໄປ."</string>
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ສົ່ງການກະຈາຍຄະແນນເຄືອຂ່າຍ"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ອະນຸຍາດໃຫ້ແອັບຯກະຈາຍການແຈ້ງເຕືອນທີ່ເຄືອຂ່າຍຕ່າງໆຈຳເປັນຖືກໃຊ້ນັບຄະແນນ. ບໍ່ມີຄວາມຈຳເປັນໃນແອັບຯທົ່ວໄປ."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ຈຳກັດຈຳນວນຂອງໂປຣເຊສທີ່ເຮັດວຽກຢູ່"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມຈຳນວນສູງສຸດ ຂອງໂປຣເຊສທີ່ຈະເຮັດວຽກ. ບໍ່ຄວນຖືກໃຊ້ກັບແອັບພລິເຄຊັນທົ່ວໄປ."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"ບັງຄັບໃຫ້ແອັບຯທີ່ເຮັດວຽກຢູ່ພື້ນຫຼັງປິດໂຕລົງ"</string>
@@ -642,7 +644,7 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"ປ່ຽນສະຖານະ WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"ອະນຸຍາດໃຫ້ແອັບຯເຊື່ອມຕໍ່ ແລະຕັດການເຊື່ອມຕໍ່ແທັບເລັດຈາກເຄືອຂ່າຍ WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"ອະນຸຍາດໃຫ້ແອັບຯເຊື່ອມຕໍ່ ແລະຕັດການເຊື່ອມຕໍ່ຂອງໂທລະສັບຈາກເຄືອຂ່າຍ WiMax ໄດ້."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ເຄືອຂ່າຍຄະແນນ"</string>
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ຄະແນນເຄືອຂ່າຍ"</string>
<string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ອະນຸຍາດໃຫ້ແອັບຯຈັດລຳດັບເຄືອຂ່າຍ ແລະ ຊ່ວຍຕັດສິນໃຈວ່າເຄືອຂ່າຍໃດທີ່ແທັບເລັດຄວນນຳໃຊ້."</string>
<string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ອະນຸຍາດໃຫ້ແອັບຯຈັດລຳດັບເຄືອຂ່າຍ ແລະ ຊ່ວຍຕັດສິນໃຈວ່າເຄືອຂ່າຍໃດທີ່ໂທລະສັບຄວນນຳໃຊ້."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ຈັບຄູ່ກັບອຸປະກອນ Bluetooth"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f10135b..c8724a3 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lėktuvo režimas"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ĮJUNGTAS lėktuvo režimas"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"lėktuvo režimas IŠJUNGTAS"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Nustatymai"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
<string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f53f0ca..f2aec67 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lidojuma režīms"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lidojuma režīms ir IESLĒGTS."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lidojuma režīms ir IZSLĒGTS."</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Iestatījumi"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
<string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index f5f8fd3..1006907f 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Нислэгийн горим"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Нислэгийн горим асав"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Нислэгийн горим унтарсан"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Тохиргоо"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index aee4cdf..d3b5987 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod pesawat"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mod Pesawat DIHIDUPKAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mod Pesawat DIMATIKAN"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
@@ -390,10 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <!-- no translation found for permlab_bindRouteProvider (4869394607915096847) -->
- <skip />
- <!-- no translation found for permdesc_bindRouteProvider (4703804520859960329) -->
- <skip />
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"terikat kepada perkhidmatan pembekal laluan"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Membenarkan pemegang untuk terikat kepada mana-mana pembekal laluan yang berdaftar. Tidak sekali-kali diperlukan untuk apl normal."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Membenarkan pemegang menghantar tujuan kepada pentadbir peranti. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ikat kepada input TV"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 029ceb5..d95d6f1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flymodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flymodus er på"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flymodus er av"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5010748..c629254 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Instellingen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c8d7298..34d43de 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Tryb samolotowy"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Tryb samolotowy jest włączony"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Tryb samolotowy jest wyłączony"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Ustawienia"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
<string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 718c8d9..6996d13 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo de voo está ativado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo de voo está desativado"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Definições"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 29a294a7..a0124ca 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index e362590..dc710d4 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -218,6 +218,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modus d\'aviun"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Il modus d\'aviun è activà"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Il modus d\'aviun è deactivà."</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<!-- no translation found for status_bar_notification_info_overflow (5301981741705354993) -->
<skip />
<string name="safeMode" msgid="2788228061547930246">"Modus segirà"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c173eef..0757578 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modul Avion este ACTIVAT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modul avion este DEZACTIVAT"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a3d5d92..f826f1a 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим полета"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Выключить"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Включить"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e9f3adc..09cf7f6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V lietadle"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V lietadle je ZAPNUTÝ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V lietadle je VYPNUTÝ"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 6d4f21c..00649f4 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način za letalo"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Način za letalo je VKLOPLJEN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Način za letalo je IZKLOPLJEN"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Nastavitve"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 1a3a235..d363771 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим рада у авиону"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим рада у авиону је УКЉУЧЕН"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим рада у авиону је ИСКЉУЧЕН"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
@@ -899,7 +901,7 @@
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Откључавање налога"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Превише покушаја уноса шаблона"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Корисничко име (адреса е-поште)"</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Корисничко име (имејл адреса)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Лозинка"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Пријави ме"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Неважеће корисничко име или лозинка."</string>
@@ -1556,7 +1558,7 @@
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (адреса е-поште)"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (имејл адреса)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 03dc691..7ec4f41 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flygplansläge"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flygplansläge är AKTIVERAT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flygplansläge är INAKTIVERAT"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Inställningar"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 71f5003..40adc3e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Hali ya ndege"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Hali ya ndege IMEWASHWA"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Hali ya ndege IMEZIMWA"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
<string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
@@ -390,8 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Huruhusu mtumiaji kujifungia kiolesura cha kiwango cha juu cha mwonekano wa mbali. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"shurutisha kwenye huduma ya mtoa huduma wa njia"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Huruhusu mmiliki kushurutisha kwenye watoa huduma wa njia waliosajiliwa. Haipaswi kuhitajika kwa programu za kawaida."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bandika kwenye huduma ya mtoa huduma za njia"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Huruhusu mmiliki kubandika kwenye watoa huduma za njia waliosajiliwa. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Inamruhusu mmiliki kutuma malengo kwa msimamizi wa kifaa. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bandika kwenye zana za data ya runinga"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index b8d99b0..c211018 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"โหมดใช้งานบนเครื่องบิน"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"เปิดโหมดใช้งานบนเครื่องบิน"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"โหมดใช้งานบนเครื่องบินปิดทำงานอยู่"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"การตั้งค่า"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
<string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
@@ -331,8 +332,8 @@
<string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ช่วยให้เจ้าของสามารถดึงข้อมูลส่วนตัวเกี่ยวกับแอปพลิเคชันปัจจุบันในส่วนหน้าของหน้าจอ"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ตรวจสอบและควบคุมแอปพลิเคชันทั้งหมดที่เปิดใช้งาน"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"อนุญาตให้แอปพลิเคชันตรวจสอบและควบคุมวิธีการที่ระบบเปิดกิจกรรมต่างๆ แอปพลิเคชันที่เป็นอันตรายอาจทำอันตรายแก่ระบบได้อย่างสิ้นเชิง การอนุญาตนี้จำเป็นสำหรับการพัฒนาเท่านั้น ไม่ใช้สำหรับแอปพลิเคชันทั่วไปโดยเด็ดขาด"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพคเกจออก"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าแพคเกจของแอปพลิเคชันหนึ่งๆ ได้ถูกนำออกไปแล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติแอปพลิเคชันอื่นๆ ที่กำลังทำงานอยู่"</string>
+ <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพ็กเกจออก"</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าแพ็กเกจของแอปพลิเคชันหนึ่งๆ ได้ถูกนำออกไปแล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติแอปพลิเคชันอื่นๆ ที่กำลังทำงานอยู่"</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"ส่งการกระจายข้อมูลว่าได้รับ SMS"</string>
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าได้รับข้อความ SMS แล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ปลอมข้อความ SMS ที่เข้ามา"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ส่งการกระจายข้อมูลว่าได้รับ WAP-PUSH"</string>
@@ -410,7 +411,7 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้แท็บเล็ตทำงานช้าลง"</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้โทรศัพท์ทำงานช้าลง"</string>
<string name="permlab_deletePackages" msgid="184385129537705938">"ลบแอปพลิเคชัน"</string>
- <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพคเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
+ <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพ็กเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
<string name="permlab_clearAppUserData" msgid="274109191845842756">"ลบข้อมูลของแอปพลิเคชันอื่น"</string>
<string name="permdesc_clearAppUserData" msgid="4625323684125459488">"อนุญาตให้แอปพลิเคชันล้างข้อมูลผู้ใช้"</string>
<string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"ลบแคชของแอปพลิเคชันอื่น"</string>
@@ -418,7 +419,7 @@
<string name="permlab_getPackageSize" msgid="7472921768357981986">"วัดพื้นที่เก็บข้อมูลของแอปพลิเคชัน"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"อนุญาตให้แอปพลิเคชันเรียกดูรหัส ข้อมูล และขนาดแคชของตน"</string>
<string name="permlab_installPackages" msgid="2199128482820306924">"ติดตั้งแอปพลิเคชันโดยตรง"</string>
- <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพคเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพ็กเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
<string name="permlab_clearAppCache" msgid="7487279391723526815">"ลบข้อมูลแคชของแอปพลิเคชันทั้งหมด"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของแท็บเล็ต โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
<string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของโทรศัพท์ โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
@@ -944,7 +945,7 @@
<string name="hour_cap_ampm" msgid="2083465992940444366">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<string name="factorytest_failed" msgid="5410270329114212041">"การทดสอบจากโรงงานล้มเหลว"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"การทำงาน FACTORY_TEST ได้รับการสนับสนุนเฉพาะสำหรับแพ็คเก็จที่ติดตั้งใน /system/app เท่านั้น"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"ไม่พบแพคเกจที่มีการทำงาน FACTORY_TEST"</string>
+ <string name="factorytest_no_action" msgid="872991874799998561">"ไม่พบแพ็กเกจที่มีการทำงาน FACTORY_TEST"</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"รีบูต"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"หน้าเว็บที่ \"<xliff:g id="TITLE">%s</xliff:g>\" ระบุว่า:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
@@ -983,10 +984,10 @@
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"อนุญาตให้แอปพลิเคชันเพิ่มข้อความลงในกล่องข้อความเสียงของคุณ"</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"แก้ไขการอนุญาตเกี่ยวกับการระบุตำแหน่งทางภูมิศาสตร์ของเบราว์เซอร์"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"อนุญาตให้แอปพลิเคชันแก้ไขการอนุญาตตำแหน่งทางภูมิศาสตร์ของเบราว์เซอร์ แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการส่งข้อมูลตำแหน่งไปยังเว็บไซต์ต่างๆ ได้ตามต้องการ"</string>
- <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ยืนยันแพคเกจ"</string>
- <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพคเกจสามารถติดตั้งได้หรือไม่"</string>
- <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพคเกจ"</string>
- <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ยืนยันแพ็กเกจ"</string>
+ <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพ็กเกจสามารถติดตั้งได้หรือไม่"</string>
+ <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพ็กเกจ"</string>
+ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพ็กเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"เข้าถึงผู้ให้บริการเนื้อหาจากภายนอก"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 394f01e..a7b7b8f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Airplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Naka-ON ang airplane mode"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Naka-OFF ang airplane mode"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index cde7219..bc73a93f8 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Uçak modu"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index f55fcf3..75d77c8 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим польоту"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим польоту ВВІМК."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим польоту ВИМК."</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Налаштування"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 841a68d..a1c03ad 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -175,6 +175,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Chế độ trên máy bay"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Chế độ trên máy bay BẬT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Chế độ trên máy bay TẮT"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
<string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 020484e..134cf9a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飞行模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
@@ -643,8 +645,8 @@
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允许该应用建立和断开平板电脑与 WiMAX 网络之间的连接。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允许该应用建立和断开手机与 WiMAX 网络之间的连接。"</string>
<string name="permlab_scoreNetworks" msgid="6445777779383587181">"为网络评分"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允许应用为网络排名,并控制平板电脑应优先使用的网络。"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允许应用为网络排名,并控制手机应优先使用的网络。"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允许应用为网络评分,并控制平板电脑应优先使用的网络。"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允许应用为网络评分,并控制手机应优先使用的网络。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"与蓝牙设备配对"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允许该应用查看平板电脑上的蓝牙配置,以及建立和接受与配对设备的连接。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允许该应用查看手机上的蓝牙配置,以及建立和接受与配对设备的连接。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 8841536..2d3c418 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛行模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛行模式為 [關閉]"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index bab94b4..e309acc 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛航模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛航模式為 [關閉]"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
@@ -338,7 +340,7 @@
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"送出「WAP PUSH 已接收」廣播"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允許應用程式在收到 WAP PUSH 訊息時發送通知。請注意,惡意應用程式可能利用此功能偽造 MMS 簡訊回條,或私自將網頁內容更換為惡意陷阱。"</string>
<string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"傳送網路計分廣播通知"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允許應用程式廣播網路需計分的通知訊息 (一般應用程式並不需要)。"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允許應用程式廣播「網路需計分」的通知訊息 (一般應用程式並不需要)。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程序限制數"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允許應用程式控制可執行程序的數量上限 (一般應用程式不需使用)。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"強制關閉背景應用程式"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4dbd003..4e36a1b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Imodi yendiza"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Imodi yendiza IVULIWE"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Imodi yendiza IVALIWE"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Izilungiselelo"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
<string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b7bffde..abac60e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2191,6 +2191,9 @@
(completely opaque). -->
<attr name="alpha" format="float" />
+ <!-- base z depth of the view -->
+ <attr name="elevation" format="dimension" />
+
<!-- translation in x of the view. This value is added post-layout to the left
property of the view, which is set by its layout. -->
<attr name="translationX" format="dimension" />
@@ -2199,7 +2202,7 @@
property of the view, which is set by its layout. -->
<attr name="translationY" format="dimension" />
- <!-- translation in z of the view. This value is added post-layout to its position. -->
+ <!-- translation in z of the view. This value is added to its elevation. -->
<attr name="translationZ" format="dimension" />
<!-- x location of the pivot point around which the view will rotate and scale.
@@ -2357,6 +2360,10 @@
Activity to UI element in the called Activity. Names should be unique in the
View hierarchy. -->
<attr name="sharedElementName" format="string" />
+
+ <!-- Specifies that this view should permit nested scrolling within a compatible
+ ancestor view. -->
+ <attr name="nestedScrollingEnabled" format="boolean" />
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -6263,13 +6270,22 @@
</declare-styleable>
<!-- Use <code>recognition-service</code> as the root tag of the XML resource that
- describes a {@link android.speech.RecognitionService}, which is reference from
+ describes a {@link android.speech.RecognitionService}, which is referenced from
its {@link android.speech.RecognitionService#SERVICE_META_DATA} meta-data entry.
Described here are the attributes that can be included in that tag. -->
<declare-styleable name="RecognitionService">
<attr name="settingsActivity" />
</declare-styleable>
+ <!-- Use <code>voice-interaction-service</code> as the root tag of the XML resource that
+ describes a {@link android.service.voice.VoiceInteractionService}, which is referenced from
+ its {@link android.service.voice.VoiceInteractionService#SERVICE_META_DATA} meta-data entry.
+ Described here are the attributes that can be included in that tag. -->
+ <declare-styleable name="VoiceInteractionService">
+ <attr name="sessionService" format="string" />
+ <attr name="settingsActivity" />
+ </declare-styleable>
+
<!-- Attributes used to style the Action Bar. -->
<declare-styleable name="ActionBar">
<!-- The type of navigation to use. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b14453a..cce4dbd 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -746,7 +746,14 @@
selected a new global font size. -->
<flag name="fontScale" value="0x40000000" />
</attr>
-
+
+ <!-- Indicate that the activity can be launched as the embedded child of another
+ activity. Particularly in the case where the child lives in a container
+ such as a Display owned by another activity.
+
+ <p>The default value of this attribute is <code>false</code>. -->
+ <attr name="allowEmbedded" format="boolean" />
+
<!-- Descriptive text for the associated data. -->
<attr name="description" format="reference" />
@@ -1541,6 +1548,7 @@
primary user. Can only be used with receivers. -->
<attr name="primaryUserOnly" format="boolean" />
<attr name="persistable" />
+ <attr name="allowEmbedded" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
index 02e61e2..cebee12 100644
--- a/core/res/res/values/dimens_quantum.xml
+++ b/core/res/res/values/dimens_quantum.xml
@@ -47,4 +47,6 @@
<dimen name="text_size_menu_quantum">14sp</dimen>
<dimen name="text_size_button_quantum">14sp</dimen>
+ <dimen name="floating_window_z">16dp</dimen>
+ <dimen name="floating_window_margin">32dp</dimen>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9712c03..85ef004 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2094,7 +2094,8 @@
<public type="attr" name="banner" id="0x10103f2" />
<public type="attr" name="windowSwipeToDismiss" id="0x10103f3" />
- <public type="attr" name="isGame" />
+ <public type="attr" name="isGame" id="0x10103f4" />
+ <public type="attr" name="allowEmbedded" id="0x10103f5" />
<!-- ===============================================================
Resources added in version 21 of the platform
@@ -2153,6 +2154,16 @@
<public type="attr" name="colorPrimary" />
<public type="attr" name="colorPrimaryDark" />
<public type="attr" name="colorAccent" />
+ <public type="attr" name="nestedScrollingEnabled" />
+ <public type="attr" name="windowEnterTransition" />
+ <public type="attr" name="windowExitTransition" />
+ <public type="attr" name="windowSharedElementEnterTransition" />
+ <public type="attr" name="windowSharedElementExitTransition" />
+ <public type="attr" name="windowAllowExitTransitionOverlap" />
+ <public type="attr" name="windowAllowEnterTransitionOverlap" />
+ <public type="attr" name="sessionService" />
+ <public type="attr" name="switchStyle" />
+ <public type="attr" name="elevation" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
@@ -2383,17 +2394,14 @@
<public type="style" name="Widget.Holo.Light.Button.Borderless" />
+ <public-padding type="interpolator" name="l_resource_pad" end="0x010c0010" />
+
<!-- An interpolator which accelerates fast but decelerates slowly. -->
<public type="interpolator" name="fast_out_slow_in" />
<!-- An interpolator which starts with a peak non-zero velocity and decelerates slowly. -->
<public type="interpolator" name="linear_out_slow_in" />
<!-- An interpolator which accelerates fast and keeps accelerating until the end. -->
<public type="interpolator" name="fast_out_linear_in" />
- <public type="attr" name="windowEnterTransition" />
- <public type="attr" name="windowExitTransition" />
- <public type="attr" name="windowSharedElementEnterTransition" />
- <public type="attr" name="windowSharedElementExitTransition" />
- <public type="attr" name="windowAllowExitTransitionOverlap" />
- <public type="attr" name="windowAllowEnterTransitionOverlap" />
+
<public type="transition" name="no_transition" id="0x010f0000"/>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6d4ceef..cb52db2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1068,6 +1068,12 @@
interface of a wallpaper. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindVoiceInteraction">bind to a voice interactor</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindVoiceInteraction">Allows the holder to bind to the top-level
+ interface of a voice interaction service. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindRemoteDisplay">bind to a remote display</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
@@ -2048,6 +2054,11 @@
<string name="permdesc_bindNotificationListenerService">Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindConditionProviderService">bind to a condition provider service</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindConditionProviderService">Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_invokeCarrierSetup">invoke the carrier-provided configuration app</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_invokeCarrierSetup">Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps.</string>
@@ -3797,6 +3808,8 @@
<!-- Label to show for a service that is running because it is observing
the user's notifications. -->
<string name="notification_listener_binding_label">Notification listener</string>
+ <!-- Label to show for a service that is running because it is providing conditions. -->
+ <string name="condition_provider_service_binding_label">Condition provider</string>
<!-- Do Not Translate: Alternate eri.xml -->
<string name="alternate_eri_file">/data/eri.xml</string>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 0cbb655..57f2443 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -480,7 +480,7 @@
<style name="Widget.Quantum.AbsListView" parent="Widget.AbsListView"/>
<style name="Widget.Quantum.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
- <item name="dropDownSelector">@drawable/list_selector_holo_dark</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
</style>
@@ -654,7 +654,7 @@
<style name="Widget.Quantum.Spinner" parent="Widget.Spinner.DropDown">
<item name="background">@drawable/spinner_background_quantum</item>
- <item name="dropDownSelector">@drawable/list_selector_holo_dark</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
@@ -713,7 +713,7 @@
<style name="Widget.Quantum.QuickContactBadgeSmall.WindowLarge" parent="Widget.QuickContactBadgeSmall.WindowLarge"/>
<style name="Widget.Quantum.ListPopupWindow" parent="Widget.ListPopupWindow">
- <item name="dropDownSelector">@drawable/list_selector_holo_dark</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
@@ -851,7 +851,7 @@
<style name="Widget.Quantum.Light.AbsListView" parent="Widget.Quantum.AbsListView"/>
<style name="Widget.Quantum.Light.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
- <item name="dropDownSelector">@drawable/list_selector_holo_light</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
</style>
@@ -938,7 +938,7 @@
<style name="Widget.Quantum.Light.Spinner" parent="Widget.Quantum.Spinner">
<item name="background">@drawable/spinner_background_quantum</item>
- <item name="dropDownSelector">@drawable/list_selector_holo_light</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
@@ -962,7 +962,7 @@
<style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowLarge" parent="Widget.Quantum.QuickContactBadgeSmall.WindowLarge"/>
<style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.ListPopupWindow">
- <item name="dropDownSelector">@drawable/list_selector_holo_light</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
@@ -1019,16 +1019,16 @@
<!-- Dialog styles -->
<style name="AlertDialog.Quantum" parent="AlertDialog">
- <item name="fullDark">?attr/colorBackground</item>
- <item name="topDark">?attr/colorBackground</item>
- <item name="centerDark">?attr/colorBackground</item>
- <item name="bottomDark">?attr/colorBackground</item>
- <item name="fullBright">?attr/colorBackground</item>
- <item name="topBright">?attr/colorBackground</item>
- <item name="centerBright">?attr/colorBackground</item>
- <item name="bottomBright">?attr/colorBackground</item>
- <item name="bottomMedium">?attr/colorBackground</item>
- <item name="centerMedium">?attr/colorBackground</item>
+ <item name="fullDark">@color/transparent</item>
+ <item name="topDark">@color/transparent</item>
+ <item name="centerDark">@color/transparent</item>
+ <item name="bottomDark">@color/transparent</item>
+ <item name="fullBright">@color/transparent</item>
+ <item name="topBright">@color/transparent</item>
+ <item name="centerBright">@color/transparent</item>
+ <item name="bottomBright">@color/transparent</item>
+ <item name="bottomMedium">@color/transparent</item>
+ <item name="centerMedium">@color/transparent</item>
<item name="layout">@layout/alert_dialog_quantum</item>
<item name="listLayout">@layout/select_dialog_quantum</item>
<item name="progressLayout">@layout/progress_dialog_quantum</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bc92107..6e33bed 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -233,7 +233,6 @@
<java-symbol type="attr" name="searchDialogTheme" />
<java-symbol type="attr" name="searchViewSearchIcon" />
<java-symbol type="attr" name="stackViewStyle" />
- <java-symbol type="attr" name="switchStyle" />
<java-symbol type="attr" name="textAppearanceAutoCorrectionSuggestion" />
<java-symbol type="attr" name="textAppearanceEasyCorrectSuggestion" />
<java-symbol type="attr" name="textAppearanceMisspelledSuggestion" />
@@ -1580,6 +1579,7 @@
<java-symbol type="string" name="low_internal_storage_view_text" />
<java-symbol type="string" name="low_internal_storage_view_title" />
<java-symbol type="string" name="notification_listener_binding_label" />
+ <java-symbol type="string" name="condition_provider_service_binding_label" />
<java-symbol type="string" name="report" />
<java-symbol type="string" name="select_input_method" />
<java-symbol type="string" name="select_keyboard_layout_notification_title" />
@@ -1801,6 +1801,7 @@
<java-symbol type="attr" name="amPmSelectedBackgroundColor" />
<java-symbol type="attr" name="numbersSelectorColor" />
<java-symbol type="attr" name="timePickerHeaderTimeLabelTextAppearance" />
+ <java-symbol type="attr" name="nestedScrollingEnabled" />
<java-symbol type="style" name="TextAppearance.Holo.TimePicker.TimeLabel" />
<java-symbol type="layout" name="time_picker_holo" />
<java-symbol type="layout" name="time_header_label" />
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index c2e31f4..9f76eae 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -125,7 +125,7 @@
<item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
<item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
- <item name="listChoiceBackgroundIndicator">@drawable/list_selector_holo_dark</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
<item name="activatedBackgroundIndicator">@drawable/activated_background_quantum</item>
@@ -468,7 +468,7 @@
<item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
<item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
- <item name="listChoiceBackgroundIndicator">@drawable/list_selector_holo_light</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
<item name="activatedBackgroundIndicator">@drawable/activated_background_quantum</item>
@@ -898,7 +898,7 @@
<style name="Theme.Quantum.Dialog">
<item name="windowFrame">@null</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
- <item name="windowBackground">?attr/colorBackground</item>
+ <item name="windowBackground">@drawable/dialog_background_quantum</item>
<item name="windowIsFloating">true</item>
<item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@style/Animation.Quantum.Dialog</item>
@@ -964,8 +964,6 @@
its pixels. -->
<style name="Theme.Quantum.Dialog.NoFrame">
<item name="windowBackground">@color/transparent</item>
- <item name="windowFrame">@null</item>
- <item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@null</item>
<item name="backgroundDimEnabled">false</item>
<item name="windowIsTranslucent">true</item>
@@ -981,7 +979,6 @@
<style name="Theme.Quantum.Dialog.Alert">
<item name="windowBackground">@color/transparent</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
- <item name="windowContentOverlay">@null</item>
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
@@ -1102,7 +1099,6 @@
<style name="Theme.Quantum.Light.Dialog.Alert">
<item name="windowBackground">@color/transparent</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
- <item name="windowContentOverlay">@null</item>
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
@@ -1112,7 +1108,6 @@
<style name="Theme.Quantum.Light.Dialog.TimePicker">
<item name="windowBackground">@color/transparent</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
- <item name="windowContentOverlay">@null</item>
</style>
<!-- Theme for a presentation window on a secondary display. -->
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index e77564f..07a6a10 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -16,7 +16,7 @@
package android.content.pm;
-import static libcore.io.OsConstants.*;
+import static android.system.OsConstants.*;
import com.android.frameworks.coretests.R;
import com.android.internal.content.PackageHelper;
@@ -48,6 +48,9 @@
import android.os.storage.StorageResultCode;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
@@ -62,10 +65,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.StructStat;
-
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
@@ -503,7 +502,7 @@
final StructStat stat;
try {
- stat = Libcore.os.lstat(path);
+ stat = Os.lstat(path);
} catch (ErrnoException e) {
throw new AssertionError(reason + "\n" + "Got: " + path + " does not exist");
}
diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java
index 17423be..bccf556 100644
--- a/core/tests/coretests/src/android/net/LinkAddressTest.java
+++ b/core/tests/coretests/src/android/net/LinkAddressTest.java
@@ -32,13 +32,13 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import static libcore.io.OsConstants.IFA_F_DEPRECATED;
-import static libcore.io.OsConstants.IFA_F_PERMANENT;
-import static libcore.io.OsConstants.IFA_F_TENTATIVE;
-import static libcore.io.OsConstants.RT_SCOPE_HOST;
-import static libcore.io.OsConstants.RT_SCOPE_LINK;
-import static libcore.io.OsConstants.RT_SCOPE_SITE;
-import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE;
+import static android.system.OsConstants.IFA_F_DEPRECATED;
+import static android.system.OsConstants.IFA_F_PERMANENT;
+import static android.system.OsConstants.IFA_F_TENTATIVE;
+import static android.system.OsConstants.RT_SCOPE_HOST;
+import static android.system.OsConstants.RT_SCOPE_LINK;
+import static android.system.OsConstants.RT_SCOPE_SITE;
+import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
/**
* Tests for {@link LinkAddress}.
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index a602e07..553afe0 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -18,14 +18,13 @@
import android.net.LinkProperties;
import android.net.RouteInfo;
+import android.system.OsConstants;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
import java.net.InetAddress;
import java.util.ArrayList;
-import libcore.io.OsConstants;
-
public class LinkPropertiesTest extends TestCase {
private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
diff --git a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java b/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
index 0e3c13a0..3f9e62e 100644
--- a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
@@ -46,7 +46,6 @@
import junit.framework.Assert;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
/**
* Tests for {@link FileRotator}.
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 4903852..f09ff9e 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -899,8 +899,9 @@
{@code tools/} path:
<pre class="no-pretty-print">adb shell bmgr enable true</pre>
</li>
- <li>If using a device, open the system <b>Settings</b>, select <b>Privacy</b>, then enable
-<b>Back up my data</b> and <b>Automatic restore</b>.
+ <li>If using a device, open the system <b>Settings</b>, select
+ <b>Backup & reset</b>, then enable
+ <b>Back up my data</b> and <b>Automatic restore</b>.</li>
</ul>
</li>
<li>Open your application and initialize some data
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index 20dc4ea..7717696 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -30,7 +30,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html"><permission-group></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html"><permission-tree></a></code>
-<br/><code><a href="{@docRoot}guide/topics/manifest/supports-gl-texture.html"><supports-gl-texture></a></code
+<br/><code><a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html"><supports-gl-texture></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></code> <!-- ##api level 3## -->
<br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a></code>
@@ -193,4 +193,4 @@
<dd>
<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code></dd>
-</dl>
\ No newline at end of file
+</dl>
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index e4cf1bc..e12dfd8 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
page.title=Installing the Eclipse Plugin
-adt.zip.version=22.6.2
-adt.zip.download=ADT-22.6.2.zip
-adt.zip.bytes=14586842
-adt.zip.checksum=f660959fa71262b4285bcb64be284bf5
+adt.zip.version=22.6.3
+adt.zip.download=ADT-22.6.3.zip
+adt.zip.bytes=14590813
+adt.zip.checksum=3982259fd2cc81e53bbbe05dcd6529a7
@jd:body
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index d106f4a..124e58d 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -53,10 +53,49 @@
<p>For a summary of all known issues in ADT, see <a
href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
-
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>ADT 22.6.3</a> <em>(April 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.6.3</a>.
+ If you haven't already installed SDK Tools r22.6.3 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed a problem where the AVD manager allowed creating Android Wear virtual devices
+ with a target API Level lower than 19.</li>
+ <li>Fixed the description of Android Wear system images in the SDK Manager.</li>
+ </ul>
+ </dd>
+
+ <dt>Known Issues:</dt>
+ <dd>
+ <p>When you create an Android Wear virtual device in the AVD manager, a target API Level
+ lower than 19 may be selected by default. Make sure you select the target API Level 19
+ when creating Android Wear virtual devices.</p>
+ </dd>
+</dl>
+</div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>ADT 22.6.2</a> <em>(March 2014)</em>
</p>
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index a22dc90..0ac1881 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -245,8 +245,8 @@
but it always increases your app complexity. In general, you should only use the NDK
if it is essential to your app—never because you simply prefer to program in C/C++.</p>
- <p>Typical good candidates for the NDK are self-contained, CPU-intensive operations that don't
- allocate much memory, such as signal processing, physics simulation, and so on. When examining
+ <p>Typical good candidates for the NDK are CPU-intensive workloads such as game engines,
+ signal processing, physics simulation, and so on. When examining
whether or not you should develop in native code, think about your requirements and see if the
Android framework APIs provide the functionality that you need.</p>
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 14b5505..9b06a9d 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,6 +28,46 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 22.6.3</a> <em>(April 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 18 or later.</li>
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+ designed for use with ADT 22.6.3 and later. If you haven't already, update your
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.6.3.</li>
+ <li>If you are developing outside Eclipse, you must have
+ <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed a problem where the AVD manager allowed creating Android Wear virtual devices
+ with a target API Level lower than 19.</li>
+ <li>Fixed the description of Android Wear system images in the SDK Manager.</li>
+ </ul>
+ </dd>
+
+ <dt>Known Issues:</dt>
+ <dd>
+ <p>When you create an Android Wear virtual device in the AVD manager, a target API Level
+ lower than 19 may be selected by default. Make sure you select the target API Level 19
+ when creating Android Wear virtual devices.</p>
+ </dd>
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>SDK Tools, Revision 22.6.2</a> <em>(March 2014)</em>
</p>
diff --git a/drm/java/android/drm/DrmOutputStream.java b/drm/java/android/drm/DrmOutputStream.java
index 22e7ac2..ba1c56f 100644
--- a/drm/java/android/drm/DrmOutputStream.java
+++ b/drm/java/android/drm/DrmOutputStream.java
@@ -18,14 +18,14 @@
import static android.drm.DrmConvertedStatus.STATUS_OK;
import static android.drm.DrmManagerClient.INVALID_SESSION;
-import static libcore.io.OsConstants.SEEK_SET;
+import static android.system.OsConstants.SEEK_SET;
import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
-import libcore.io.ErrnoException;
import libcore.io.IoBridge;
-import libcore.io.Libcore;
import libcore.io.Streams;
import java.io.FileDescriptor;
@@ -69,7 +69,7 @@
final DrmConvertedStatus status = mClient.closeConvertSession(mSessionId);
if (status.statusCode == STATUS_OK) {
try {
- Libcore.os.lseek(mFd, status.offset, SEEK_SET);
+ Os.lseek(mFd, status.offset, SEEK_SET);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index f80ce28..ae3eae1 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1075,11 +1075,20 @@
* @param paint The paint used to draw the roundRect
*/
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
- if (rect == null) {
- throw new NullPointerException();
- }
- native_drawRoundRect(mNativeCanvas, rect, rx, ry,
- paint.mNativePaint);
+ drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
+ }
+
+ /**
+ * Draw the specified round-rect using the specified paint. The roundrect
+ * will be filled or framed based on the Style in the paint.
+ *
+ * @param rx The x-radius of the oval used to round the corners
+ * @param ry The y-radius of the oval used to round the corners
+ * @param paint The paint used to draw the roundRect
+ */
+ public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ Paint paint) {
+ native_drawRoundRect(mNativeCanvas, left, top, right, bottom, rx, ry, paint.mNativePaint);
}
/**
@@ -1816,8 +1825,8 @@
boolean useCenter,
long nativePaint);
private static native void native_drawRoundRect(long nativeCanvas,
- RectF rect, float rx,
- float ry, long nativePaint);
+ float left, float top, float right, float bottom,
+ float rx, float ry, long nativePaint);
private static native void native_drawPath(long nativeCanvas,
long nativePath,
long nativePaint);
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 4ea7ec7..b5c0801 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -16,18 +16,21 @@
package android.graphics;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Drawable;
import android.view.View;
/**
- * Defines an area of content.
+ * Defines a simple shape, used for bounding graphical regions.
*
- * Can be used with a View or Drawable to drive the shape of shadows cast by a
- * View, and allowing Views to clip inner content.
+ * Can be used with a View, or computed by a Drawable, to drive the shape of shadows cast by a
+ * View.
*
* @see View#setOutline(Outline)
- * @see View#setClipToOutline(boolean)
+ * @see Drawable#getOutline(Outline)
*/
-public class Outline {
+public final class Outline {
/** @hide */
public Rect mRect;
@@ -44,46 +47,74 @@
public Outline() {}
/**
+ * Constructs an Outline with a copy of the data in src.
+ */
+ public Outline(@Nullable Outline src) {
+ set(src);
+ }
+
+ /** @hide */
+ public void markInvalid() {
+ mRadius = 0;
+ mRect = null;
+ mPath = null;
+ }
+
+ /**
* Returns whether the Outline is valid for use with a View.
* <p>
* Outlines are invalid when constructed until a setter method is called.
*/
- public final boolean isValid() {
+ public boolean isValid() {
return mRect != null || mPath != null;
}
/**
- * @hide
- */
- public final boolean canClip() {
- return mPath == null;
- }
-
- /**
* Replace the contents of this Outline with the contents of src.
+ *
+ * @param src Source outline to copy from.
*/
- public void set(Outline src) {
- if (src.mPath != null) {
- if (mPath == null) {
- mPath = new Path();
- }
- mPath.set(src.mPath);
+ public void set(@Nullable Outline src) {
+ if (src == null) {
+ mRadius = 0;
mRect = null;
- }
- if (src.mRect != null) {
- if (mRect == null) {
- mRect = new Rect();
+ mPath = null;
+ } else {
+ if (src.mPath != null) {
+ if (mPath == null) {
+ mPath = new Path();
+ }
+ mPath.set(src.mPath);
+ mRect = null;
}
- mRect.set(src.mRect);
+ if (src.mRect != null) {
+ if (mRect == null) {
+ mRect = new Rect();
+ }
+ mRect.set(src.mRect);
+ }
+ mRadius = src.mRadius;
}
- mRadius = src.mRadius;
}
/**
* Sets the Outline to the rounded rect defined by the input rect, and corner radius.
- * <p>
- * Outlines produced by this method support
- * {@link View#setClipToOutline(boolean) View clipping.}
+ */
+ public void setRect(int left, int top, int right, int bottom) {
+ setRoundRect(left, top, right, bottom, 0.0f);
+ }
+
+ /**
+ * Convenience for {@link #setRect(int, int, int, int)}
+ */
+ public void setRect(@NonNull Rect rect) {
+ setRect(rect.left, rect.top, rect.right, rect.bottom);
+ }
+
+ /**
+ * Sets the Outline to the rounded rect defined by the input rect, and corner radius.
+ *
+ * Passing a zero radius is equivalent to calling {@link #setRect(int, int, int, int)}
*/
public void setRoundRect(int left, int top, int right, int bottom, float radius) {
if (mRect == null) mRect = new Rect();
@@ -93,11 +124,33 @@
}
/**
- * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}.
- *
- * @hide
+ * Convenience for {@link #setRoundRect(int, int, int, int, float)}
*/
- public void setConvexPath(Path convexPath) {
+ public void setRoundRect(@NonNull Rect rect, float radius) {
+ setRoundRect(rect.left, rect.top, rect.right, rect.bottom, radius);
+ }
+
+ /**
+ * Sets the outline to the oval defined by input rect.
+ */
+ public void setOval(int left, int top, int right, int bottom) {
+ mRect = null;
+ if (mPath == null) mPath = new Path();
+ mPath.reset();
+ mPath.addOval(left, top, right, bottom, Path.Direction.CW);
+ }
+
+ /**
+ * Convenience for {@link #setOval(int, int, int, int)}
+ */
+ public void setOval(@NonNull Rect rect) {
+ setOval(rect.left, rect.top, rect.right, rect.bottom);
+ }
+
+ /**
+ * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}.
+ */
+ public void setConvexPath(@NonNull Path convexPath) {
if (!convexPath.isConvex()) {
throw new IllegalArgumentException("path must be convex");
}
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index c07a6da..c600f47 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -499,11 +499,7 @@
* @param dir The direction to wind the rectangle's contour
*/
public void addRect(RectF rect, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
- detectSimplePath(rect.left, rect.top, rect.right, rect.bottom, dir);
- native_addRect(mNativePath, rect, dir.nativeInt);
+ addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
}
/**
@@ -527,11 +523,17 @@
* @param dir The direction to wind the oval's contour
*/
public void addOval(RectF oval, Direction dir) {
- if (oval == null) {
- throw new NullPointerException("need oval parameter");
- }
+ addOval(oval.left, oval.top, oval.right, oval.bottom, dir);
+ }
+
+ /**
+ * Add a closed oval contour to the path
+ *
+ * @param dir The direction to wind the oval's contour
+ */
+ public void addOval(float left, float top, float right, float bottom, Direction dir) {
isSimplePath = false;
- native_addOval(mNativePath, oval, dir.nativeInt);
+ native_addOval(mNativePath, left, top, right, bottom, dir.nativeInt);
}
/**
@@ -756,10 +758,10 @@
private static native void native_arcTo(long nPath, RectF oval,
float startAngle, float sweepAngle, boolean forceMoveTo);
private static native void native_close(long nPath);
- private static native void native_addRect(long nPath, RectF rect, int dir);
private static native void native_addRect(long nPath, float left, float top,
float right, float bottom, int dir);
- private static native void native_addOval(long nPath, RectF oval, int dir);
+ private static native void native_addOval(long nPath, float left, float top,
+ float right, float bottom, int dir);
private static native void native_addCircle(long nPath, float x, float y, float radius, int dir);
private static native void native_addArc(long nPath, RectF oval,
float startAngle, float sweepAngle);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 74d1219..b9d5e19 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -864,22 +864,21 @@
}
/**
- * Returns the outline for this drawable if defined, null if not.
+ * Called to get the drawable to populate the Outline.
* <p>
- * This method will be called by a View on its background Drawable after
- * bounds change, if the View's Outline isn't set explicitly. This allows
- * the background Drawable to provide the shape of the shadow casting
- * portion of the View. It can also serve to clip the area of the View if
- * if {@link View#setClipToOutline(boolean)} is set on the View.
- * <p>
- * The Outline queried by the View will not be modified, and is treated as
- * a static shape that only needs to be requeried when the drawable's bounds
- * change.
+ * This method will be called by a View on its background Drawable after bounds change, or its
+ * Drawable is invalidated, if the View's Outline isn't set explicitly. This allows the
+ * background Drawable to define the shape of the shadow cast by the View.
*
- * @see View#setOutline(android.view.Outline)
- * @see View#setClipToOutline(boolean)
+ * The default behavior defines the outline to be the bounding rectangle. Subclasses that wish
+ * to convey a different shape must override this method.
+ *
+ * @see View#setOutline(android.graphics.Outline)
*/
- public Outline getOutline() { return null; }
+ public boolean getOutline(Outline outline) {
+ outline.setRect(getBounds());
+ return true;
+ }
/**
* Make this drawable mutable. This operation cannot be reversed. A mutable
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 1b5cefe..dc06350 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -139,8 +139,7 @@
private final Path mPath = new Path();
private final RectF mRect = new RectF();
- private Outline mOutline;
-
+
private Paint mLayerPaint; // internal, used if we use saveLayer()
private boolean mRectIsDirty; // internal state
private boolean mMutated;
@@ -573,15 +572,11 @@
mStrokePaint.setColorFilter(mColorFilter);
}
}
-
+
switch (st.mShape) {
case RECTANGLE:
if (st.mRadiusArray != null) {
- if (mPathIsDirty || mRectIsDirty) {
- mPath.reset();
- mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
- mPathIsDirty = mRectIsDirty = false;
- }
+ buildPathIfDirty();
canvas.drawPath(mPath, mFillPaint);
if (haveStroke) {
canvas.drawPath(mPath, mStrokePaint);
@@ -638,7 +633,16 @@
}
}
}
-
+
+ private void buildPathIfDirty() {
+ final GradientState st = mGradientState;
+ if (mPathIsDirty || mRectIsDirty) {
+ mPath.reset();
+ mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
+ mPathIsDirty = mRectIsDirty = false;
+ }
+ }
+
private Path buildRing(GradientState st) {
if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
mPathIsDirty = false;
@@ -862,7 +866,7 @@
float x0, x1, y0, y1;
if (st.mGradient == LINEAR_GRADIENT) {
- final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
+ final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
switch (st.mOrientation) {
case TOP_BOTTOM:
x0 = r.left; y0 = r.top;
@@ -1428,42 +1432,40 @@
}
@Override
- public Outline getOutline() {
+ public boolean getOutline(Outline outline) {
final GradientState st = mGradientState;
final Rect bounds = getBounds();
switch (st.mShape) {
case RECTANGLE:
if (st.mRadiusArray != null) {
- return null;
+ buildPathIfDirty();
+ outline.setConvexPath(mPath);
+ return true;
}
+
float rad = 0;
if (st.mRadius > 0.0f) {
// clamp the radius based on width & height, matching behavior in draw()
rad = Math.min(st.mRadius,
Math.min(bounds.width(), bounds.height()) * 0.5f);
}
- if (mOutline == null) {
- mOutline = new Outline();
- }
- mOutline.setRoundRect(bounds.left, bounds.top,
- bounds.right, bounds.bottom, rad);
- return mOutline;
- case LINE: {
+ outline.setRoundRect(bounds, rad);
+ return true;
+ case OVAL:
+ outline.setOval(bounds);
+ return true;
+ case LINE:
float halfStrokeWidth = mStrokePaint.getStrokeWidth() * 0.5f;
float centerY = bounds.centerY();
int top = (int) Math.floor(centerY - halfStrokeWidth);
int bottom = (int) Math.ceil(centerY + halfStrokeWidth);
- if (mOutline == null) {
- mOutline = new Outline();
- }
- mOutline.setRoundRect(bounds.left, top, bounds.right, bottom, 0);
- return mOutline;
- }
+ outline.setRect(bounds.left, top, bounds.right, bottom);
+ return true;
default:
// TODO: investigate
- return null;
+ return false;
}
}
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 96309f9..61b1b85 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -21,6 +21,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
@@ -496,6 +497,16 @@
}
@Override
+ public boolean getOutline(Outline outline) {
+ if (mShapeState.mShape == null) {
+ // don't publish outline without a shape
+ return false;
+ }
+
+ return mShapeState.mShape.getOutline(outline);
+ }
+
+ @Override
public ConstantState getConstantState() {
mShapeState.mChangingConfigurations = getChangingConfigurations();
return mShapeState;
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 5101e35..0e8831f 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -48,6 +48,7 @@
public class TouchFeedbackDrawable extends LayerDrawable {
private static final String LOG_TAG = TouchFeedbackDrawable.class.getSimpleName();
private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
+ private static final PorterDuffXfermode SRC_OVER = new PorterDuffXfermode(Mode.SRC_OVER);
/** The maximum number of ripples supported. */
private static final int MAX_RIPPLES = 10;
@@ -105,6 +106,26 @@
protected boolean onStateChange(int[] stateSet) {
super.onStateChange(stateSet);
+ // TODO: Implicitly tie states to ripple IDs. For now, just clear
+ // focused and pressed if they aren't in the state set.
+ boolean hasFocused = false;
+ boolean hasPressed = false;
+ for (int i = 0; i < stateSet.length; i++) {
+ if (stateSet[i] == R.attr.state_pressed) {
+ hasPressed = true;
+ } else if (stateSet[i] == R.attr.state_focused) {
+ hasFocused = true;
+ }
+ }
+
+ if (!hasPressed) {
+ removeHotspot(R.attr.state_pressed);
+ }
+
+ if (!hasFocused) {
+ removeHotspot(R.attr.state_focused);
+ }
+
if (mRipplePaint != null && mState.mTint != null) {
final ColorStateList stateList = mState.mTint;
final int newColor = stateList.getColorForState(stateSet, 0);
@@ -122,7 +143,7 @@
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
-
+
if (!mOverrideBounds) {
mHotspotBounds.set(bounds);
}
@@ -217,6 +238,27 @@
super.inflate(r, parser, attrs, theme);
setTargetDensity(r.getDisplayMetrics());
+
+ // Find the mask
+ final int N = getNumberOfLayers();
+ for (int i = 0; i < N; i++) {
+ if (mLayerState.mChildren[i].mId == R.id.mask) {
+ mState.mMask = mLayerState.mChildren[i].mDrawable;
+ }
+ }
+ }
+
+ @Override
+ public boolean setDrawableByLayerId(int id, Drawable drawable) {
+ if (super.setDrawableByLayerId(id, drawable)) {
+ if (id == R.id.mask) {
+ mState.mMask = drawable;
+ }
+
+ return true;
+ }
+
+ return false;
}
/**
@@ -310,7 +352,7 @@
mTouchedRipples = new SparseArray<Ripple>();
mActiveRipples = new Ripple[MAX_RIPPLES];
}
-
+
if (mActiveRipplesCount >= MAX_RIPPLES) {
Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
return;
@@ -415,100 +457,144 @@
@Override
public void draw(Canvas canvas) {
- final boolean projected = getNumberOfLayers() == 0;
- final Ripple[] activeRipples = mActiveRipples;
- final int ripplesCount = mActiveRipplesCount;
+ final int N = mLayerState.mNum;
final Rect bounds = getBounds();
+ final ChildDrawable[] array = mLayerState.mChildren;
+ final boolean maskOnly = mState.mMask != null && N == 1;
+
+ int restoreToCount = drawRippleLayer(canvas, bounds, maskOnly);
+
+ if (restoreToCount >= 0) {
+ // We have a ripple layer that contains ripples. If we also have an
+ // explicit mask drawable, apply it now using DST_IN blending.
+ if (mState.mMask != null) {
+ canvas.saveLayer(bounds.left, bounds.top, bounds.right,
+ bounds.bottom, getMaskingPaint(DST_IN));
+ mState.mMask.draw(canvas);
+ canvas.restoreToCount(restoreToCount);
+ restoreToCount = -1;
+ }
+
+ // If there's more content, we need an extra masking layer to merge
+ // the ripples over the content.
+ if (!maskOnly) {
+ final PorterDuffXfermode xfermode = mState.getTintXfermodeInverse();
+ final int count = canvas.saveLayer(bounds.left, bounds.top,
+ bounds.right, bounds.bottom, getMaskingPaint(xfermode));
+ if (restoreToCount < 0) {
+ restoreToCount = count;
+ }
+ }
+ }
+
+ // Draw everything except the mask.
+ for (int i = 0; i < N; i++) {
+ if (array[i].mId != R.id.mask) {
+ array[i].mDrawable.draw(canvas);
+ }
+ }
+
+ // Composite the layers if needed.
+ if (restoreToCount >= 0) {
+ canvas.restoreToCount(restoreToCount);
+ }
+ }
+
+ private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) {
+ final int ripplesCount = mActiveRipplesCount;
+ if (ripplesCount == 0) {
+ return -1;
+ }
+
+ final Ripple[] activeRipples = mActiveRipples;
+ final boolean projected = isProjected();
+ final Rect layerBounds = projected ? getDirtyBounds() : bounds;
+
+ // Separate the ripple color and alpha channel. The alpha will be
+ // applied when we merge the ripples down to the canvas.
+ final int rippleColor;
+ if (mState.mTint != null) {
+ rippleColor = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
+ } else {
+ rippleColor = Color.TRANSPARENT;
+ }
+ final int rippleAlpha = Color.alpha(rippleColor);
+
+ if (mRipplePaint == null) {
+ mRipplePaint = new Paint();
+ mRipplePaint.setAntiAlias(true);
+ }
+ final Paint ripplePaint = mRipplePaint;
+ ripplePaint.setColor(rippleColor);
+
+ boolean drewRipples = false;
+ int restoreToCount = -1;
+ int activeRipplesCount = 0;
// Draw ripples.
- boolean drewRipples = false;
- int rippleRestoreCount = -1;
- int activeRipplesCount = 0;
for (int i = 0; i < ripplesCount; i++) {
final Ripple ripple = activeRipples[i];
final RippleAnimator animator = ripple.animate();
animator.update();
+
+ // Mark and skip inactive ripples.
if (!animator.isRunning()) {
activeRipples[i] = null;
- } else {
- // If we're masking the ripple layer, make sure we have a layer
- // first. This will merge SRC_OVER (directly) onto the canvas.
- if (!projected && rippleRestoreCount < 0) {
- rippleRestoreCount = canvas.saveLayer(bounds.left, bounds.top,
- bounds.right, bounds.bottom, null, 0);
- canvas.clipRect(bounds);
+ continue;
+ }
+
+ // If we're masking the ripple layer, make sure we have a layer
+ // first. This will merge SRC_OVER (directly) onto the canvas.
+ if (restoreToCount < 0) {
+ // If we're projecting or we only have a mask, we want to treat the
+ // underlying canvas as our content and merge the ripple layer down
+ // using the tint xfermode.
+ final PorterDuffXfermode xfermode;
+ if (projected || maskOnly) {
+ xfermode = mState.getTintXfermode();
+ } else {
+ xfermode = SRC_OVER;
}
- drewRipples |= ripple.draw(canvas, getRipplePaint());
-
- activeRipples[activeRipplesCount] = activeRipples[i];
- activeRipplesCount++;
+ final Paint layerPaint = getMaskingPaint(xfermode);
+ layerPaint.setAlpha(rippleAlpha);
+ restoreToCount = canvas.saveLayer(layerBounds.left, layerBounds.top,
+ layerBounds.right, layerBounds.bottom, layerPaint);
+ layerPaint.setAlpha(255);
}
+
+ drewRipples |= ripple.draw(canvas, ripplePaint);
+
+ activeRipples[activeRipplesCount] = activeRipples[i];
+ activeRipplesCount++;
}
+
mActiveRipplesCount = activeRipplesCount;
- // TODO: Use the masking layer first, if there is one.
-
- // If we have ripples and content, we need a masking layer. This will
- // merge DST_ATOP onto (effectively under) the ripple layer.
- if (drewRipples && !projected && rippleRestoreCount >= 0) {
- final PorterDuffXfermode xfermode = mState.getTintXfermode();
- canvas.saveLayer(bounds.left, bounds.top,
- bounds.right, bounds.bottom, getMaskingPaint(xfermode), 0);
+ // If we created a layer with no content, merge it immediately.
+ if (restoreToCount >= 0 && !drewRipples) {
+ canvas.restoreToCount(restoreToCount);
+ restoreToCount = -1;
}
- Drawable mask = null;
- final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
- for (int i = 0; i < N; i++) {
- if (array[i].mId != R.id.mask) {
- array[i].mDrawable.draw(canvas);
- } else {
- mask = array[i].mDrawable;
- }
- }
-
- // If we have ripples, mask them.
- if (mask != null && drewRipples) {
- // TODO: This will also mask the lower layer, which is bad.
- canvas.saveLayer(bounds.left, bounds.top, bounds.right,
- bounds.bottom, getMaskingPaint(DST_IN), 0);
- mask.draw(canvas);
- }
-
- // Composite the layers if needed.
- if (rippleRestoreCount >= 0) {
- canvas.restoreToCount(rippleRestoreCount);
- }
+ return restoreToCount;
}
- private Paint getRipplePaint() {
- if (mRipplePaint == null) {
- mRipplePaint = new Paint();
- mRipplePaint.setAntiAlias(true);
-
- if (mState.mTint != null) {
- final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
- mRipplePaint.setColor(color);
- }
- }
- return mRipplePaint;
- }
-
- private Paint getMaskingPaint(PorterDuffXfermode mode) {
+ private Paint getMaskingPaint(PorterDuffXfermode xfermode) {
if (mMaskingPaint == null) {
mMaskingPaint = new Paint();
}
- mMaskingPaint.setXfermode(mode);
+ mMaskingPaint.setXfermode(xfermode);
return mMaskingPaint;
}
@Override
public Rect getDirtyBounds() {
- final Rect dirtyBounds = mDirtyBounds;
final Rect drawingBounds = mDrawingBounds;
+ final Rect dirtyBounds = mDirtyBounds;
dirtyBounds.set(drawingBounds);
drawingBounds.setEmpty();
+
final Rect rippleBounds = mTempRect;
final Ripple[] activeRipples = mActiveRipples;
final int N = mActiveRipplesCount;
@@ -531,6 +617,8 @@
int[] mTouchThemeAttrs;
ColorStateList mTint;
PorterDuffXfermode mTintXfermode;
+ PorterDuffXfermode mTintXfermodeInverse;
+ Drawable mMask;
boolean mPinned;
public TouchFeedbackState(
@@ -541,19 +629,26 @@
mTouchThemeAttrs = orig.mTouchThemeAttrs;
mTint = orig.mTint;
mTintXfermode = orig.mTintXfermode;
+ mTintXfermodeInverse = orig.mTintXfermodeInverse;
mPinned = orig.mPinned;
+ mMask = orig.mMask;
}
}
-
+
public void setTintMode(Mode mode) {
final Mode invertedMode = TouchFeedbackState.invertPorterDuffMode(mode);
- mTintXfermode = new PorterDuffXfermode(invertedMode);
+ mTintXfermodeInverse = new PorterDuffXfermode(invertedMode);
+ mTintXfermode = new PorterDuffXfermode(mode);
}
-
+
public PorterDuffXfermode getTintXfermode() {
return mTintXfermode;
}
+ public PorterDuffXfermode getTintXfermodeInverse() {
+ return mTintXfermodeInverse;
+ }
+
@Override
public boolean canApplyTheme() {
return mTouchThemeAttrs != null || super.canApplyTheme();
diff --git a/graphics/java/android/graphics/drawable/shapes/OvalShape.java b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
index c914999..198dcc1 100644
--- a/graphics/java/android/graphics/drawable/shapes/OvalShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
@@ -17,7 +17,9 @@
package android.graphics.drawable.shapes;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Paint;
+import android.graphics.RectF;
/**
* Defines an oval shape.
@@ -36,5 +38,13 @@
public void draw(Canvas canvas, Paint paint) {
canvas.drawOval(rect(), paint);
}
+
+ @Override
+ public boolean getOutline(Outline outline) {
+ final RectF rect = rect();
+ outline.setOval((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
+ (int) Math.floor(rect.right), (int) Math.floor(rect.bottom));
+ return true;
+ }
}
diff --git a/graphics/java/android/graphics/drawable/shapes/RectShape.java b/graphics/java/android/graphics/drawable/shapes/RectShape.java
index a3d2654..2a0256c 100644
--- a/graphics/java/android/graphics/drawable/shapes/RectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RectShape.java
@@ -17,6 +17,7 @@
package android.graphics.drawable.shapes;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.RectF;
@@ -40,10 +41,18 @@
}
@Override
+ public boolean getOutline(Outline outline) {
+ final RectF rect = rect();
+ outline.setRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
+ (int) Math.floor(rect.right), (int) Math.floor(rect.bottom));
+ return true;
+ }
+
+ @Override
protected void onResize(float width, float height) {
mRect.set(0, 0, width, height);
}
-
+
/**
* Returns the RectF that defines this rectangle's bounds.
*/
diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
index b469d2a..a6bb1bb 100644
--- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
@@ -17,6 +17,7 @@
package android.graphics.drawable.shapes;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
@@ -77,11 +78,34 @@
public void draw(Canvas canvas, Paint paint) {
canvas.drawPath(mPath, paint);
}
-
+
+ @Override
+ public boolean getOutline(Outline outline) {
+ if (mInnerRect != null) return false; // have a hole, can't produce valid outline
+
+ float radius = 0;
+ if (mOuterRadii != null) {
+ radius = mOuterRadii[0];
+ for (int i = 1; i < 8; i++) {
+ if (mOuterRadii[i] != radius) {
+ // can't call simple constructors, use path
+ outline.setConvexPath(mPath);
+ return true;
+ }
+ }
+ }
+
+ final RectF rect = rect();
+ outline.setRoundRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
+ (int) Math.floor(rect.right), (int) Math.floor(rect.bottom),
+ radius);
+ return true;
+ }
+
@Override
protected void onResize(float w, float h) {
super.onResize(w, h);
-
+
RectF r = rect();
mPath.reset();
diff --git a/graphics/java/android/graphics/drawable/shapes/Shape.java b/graphics/java/android/graphics/drawable/shapes/Shape.java
index 4e192f95..1a20e8b 100644
--- a/graphics/java/android/graphics/drawable/shapes/Shape.java
+++ b/graphics/java/android/graphics/drawable/shapes/Shape.java
@@ -17,6 +17,7 @@
package android.graphics.drawable.shapes;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Paint;
/**
@@ -43,7 +44,6 @@
return mHeight;
}
-
/**
* Draw this shape into the provided Canvas, with the provided Paint.
* Before calling this, you must call {@link #resize(float,float)}.
@@ -52,7 +52,6 @@
* @param paint the Paint object that defines this shape's characteristics
*/
public abstract void draw(Canvas canvas, Paint paint);
-
/**
* Resizes the dimensions of this shape.
@@ -93,8 +92,20 @@
*/
protected void onResize(float width, float height) {}
+ /**
+ * Compute the Outline of the shape.
+ *
+ * The default implementation does not supply an outline.
+ *
+ * @return True if a valid outline has been computed, false otherwise.
+ */
+ public boolean getOutline(Outline outline) {
+ return false;
+ }
+
@Override
public Shape clone() throws CloneNotSupportedException {
return (Shape) super.clone();
}
+
}
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index a5d8dcb..dac86cb 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -29,7 +29,10 @@
namespace android {
namespace uirenderer {
-DisplayListData::DisplayListData() : projectionReceiveIndex(-1), functorCount(0), hasDrawOps(false) {
+DisplayListData::DisplayListData()
+ : projectionReceiveIndex(-1)
+ , functorCount(0)
+ , hasDrawOps(false) {
}
DisplayListData::~DisplayListData() {
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index f19da9d..6dfb918 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -318,12 +318,19 @@
class SaveLayerOp : public StateOp {
public:
SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags)
- : mArea(left, top, right, bottom), mPaint(&mCachedPaint), mFlags(flags) {
+ : mArea(left, top, right, bottom)
+ , mPaint(&mCachedPaint)
+ , mFlags(flags)
+ , mConvexMask(NULL) {
mCachedPaint.setAlpha(alpha);
}
SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags)
- : mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
+ : mArea(left, top, right, bottom)
+ , mPaint(paint)
+ , mFlags(flags)
+ , mConvexMask(NULL)
+ {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
bool useQuickReject) {
@@ -338,7 +345,8 @@
}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mPaint, mFlags);
+ renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom,
+ mPaint, mFlags, mConvexMask);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -350,6 +358,11 @@
int getFlags() { return mFlags; }
+ // Called to make SaveLayerOp clip to the provided mask when drawing back/restored
+ void setMask(const SkPath* convexMask) {
+ mConvexMask = convexMask;
+ }
+
private:
bool isSaveLayerAlpha() const {
SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
@@ -361,6 +374,10 @@
const SkPaint* mPaint;
SkPaint mCachedPaint;
int mFlags;
+
+ // Convex path, points at data in RenderNode, valid for the duration of the frame only
+ // Only used for masking the SaveLayer which wraps projected RenderNodes
+ const SkPath* mConvexMask;
};
class TranslateOp : public StateOp {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 6c73d68..e36d975 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -184,20 +184,15 @@
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
- // TODO: To be safe, the display list should be ref-counted in the
- // resources cache, but we rely on the caller (UI toolkit) to
- // do the right thing for now
+ if (displayList->stagingProperties().isProjectionReceiver()) {
+ // use staging property, since recording on UI thread
+ mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size();
+ }
DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList,
flags, *currentTransform());
addDrawOp(op);
mDisplayListData->addChild(op);
-
- if (displayList->stagingProperties().isProjectionReceiver()) {
- // use staging property, since recording on UI thread
- mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
- }
-
return DrawGlInfo::kStatusDone;
}
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index bfe4eda..9606e58 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -48,6 +48,7 @@
hasDrawnSinceUpdate = false;
forceFilter = false;
deferredList = NULL;
+ convexMask = NULL;
caches.resourceCache.incrementRefcount(this);
}
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 5375b45..49610d5 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -227,6 +227,14 @@
ANDROID_API void setColorFilter(SkColorFilter* filter);
+ inline void setConvexMask(const SkPath* convexMask) {
+ this->convexMask = convexMask;
+ }
+
+ inline const SkPath* getConvexMask() {
+ return convexMask;
+ }
+
void bindStencilRenderBuffer() const;
void bindTexture() const;
@@ -378,6 +386,13 @@
*/
DeferredDisplayList* deferredList;
+ /**
+ * This convex path should be used to mask the layer's draw to the screen.
+ *
+ * Data not owned/managed by layer object.
+ */
+ const SkPath* convexMask;
+
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 958cd32..4569152 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -704,11 +704,11 @@
///////////////////////////////////////////////////////////////////////////////
int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags) {
+ const SkPaint* paint, int flags, const SkPath* convexMask) {
const int count = saveSnapshot(flags);
if (!currentSnapshot()->isIgnored()) {
- createLayer(left, top, right, bottom, paint, flags);
+ createLayer(left, top, right, bottom, paint, flags, convexMask);
}
return count;
@@ -782,7 +782,6 @@
return count;
}
-
/**
* Layers are viewed by Skia are slightly different than layers in image editing
* programs (for instance.) When a layer is created, previously created layers
@@ -835,7 +834,7 @@
* something actually gets drawn are the layers regions cleared.
*/
bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags) {
+ const SkPaint* paint, int flags, const SkPath* convexMask) {
LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
@@ -865,6 +864,7 @@
layer->setBlend(true);
layer->setDirty(false);
+ layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
// Save the layer in the snapshot
mSnapshot->flags |= Snapshot::kFlagIsLayer;
@@ -1013,6 +1013,7 @@
dirtyClip();
// Failing to add the layer to the cache should happen only if the layer is too large
+ layer->setConvexMask(NULL);
if (!mCaches.layerCache.put(layer)) {
LAYER_LOGD("Deleting layer");
Caches::getInstance().resourceCache.decrementRefcount(layer);
@@ -1122,6 +1123,38 @@
#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
+ if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
+
+ if (layer->getConvexMask()) {
+ save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+
+ // clip to the area of the layer the mask can be larger
+ clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
+
+ SkiaShader* oldShader = mDrawModifiers.mShader;
+
+ // create LayerShader to map SaveLayer content into subsequent draw
+ SkMatrix shaderMatrix;
+ shaderMatrix.setTranslate(rect.left, rect.bottom);
+ shaderMatrix.preScale(1, -1);
+ SkiaLayerShader layerShader(layer, &shaderMatrix);
+ mDrawModifiers.mShader = &layerShader;
+
+ // Since the drawing primitive is defined in local drawing space,
+ // we don't need to modify the draw matrix
+ const SkPath* maskPath = layer->getConvexMask();
+ DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
+
+ mDrawModifiers.mShader = oldShader;
+ restore();
+
+ return;
+ }
+
if (layer->region.isRect()) {
layer->setRegionAsRect();
@@ -1131,88 +1164,87 @@
return;
}
- if (CC_LIKELY(!layer->region.isEmpty())) {
- size_t count;
- const android::Rect* rects;
- Region safeRegion;
- if (CC_LIKELY(hasRectToRectTransform())) {
- rects = layer->region.getArray(&count);
- } else {
- safeRegion = Region::createTJunctionFreeRegion(layer->region);
- rects = safeRegion.getArray(&count);
- }
+ // standard Region based draw
+ size_t count;
+ const android::Rect* rects;
+ Region safeRegion;
+ if (CC_LIKELY(hasRectToRectTransform())) {
+ rects = layer->region.getArray(&count);
+ } else {
+ safeRegion = Region::createTJunctionFreeRegion(layer->region);
+ rects = safeRegion.getArray(&count);
+ }
- const float alpha = getLayerAlpha(layer);
- const float texX = 1.0f / float(layer->getWidth());
- const float texY = 1.0f / float(layer->getHeight());
- const float height = rect.getHeight();
+ const float alpha = getLayerAlpha(layer);
+ const float texX = 1.0f / float(layer->getWidth());
+ const float texY = 1.0f / float(layer->getHeight());
+ const float height = rect.getHeight();
- setupDraw();
+ setupDraw();
- // We must get (and therefore bind) the region mesh buffer
- // after we setup drawing in case we need to mess with the
- // stencil buffer in setupDraw()
- TextureVertex* mesh = mCaches.getRegionMesh();
- uint32_t numQuads = 0;
+ // We must get (and therefore bind) the region mesh buffer
+ // after we setup drawing in case we need to mess with the
+ // stencil buffer in setupDraw()
+ TextureVertex* mesh = mCaches.getRegionMesh();
+ uint32_t numQuads = 0;
- setupDrawWithTexture();
- setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter(layer->getColorFilter());
- setupDrawBlending(layer);
- setupDrawProgram();
- setupDrawDirtyRegionsDisabled();
- setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms(layer->getColorFilter());
- setupDrawTexture(layer->getTexture());
- if (currentTransform()->isPureTranslate()) {
- const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
- const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
+ setupDrawWithTexture();
+ setupDrawColor(alpha, alpha, alpha, alpha);
+ setupDrawColorFilter(layer->getColorFilter());
+ setupDrawBlending(layer);
+ setupDrawProgram();
+ setupDrawDirtyRegionsDisabled();
+ setupDrawPureColorUniforms();
+ setupDrawColorFilterUniforms(layer->getColorFilter());
+ setupDrawTexture(layer->getTexture());
+ if (currentTransform()->isPureTranslate()) {
+ const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
- layer->setFilter(GL_NEAREST);
- setupDrawModelView(kModelViewMode_Translate, false,
- x, y, x + rect.getWidth(), y + rect.getHeight(), true);
- } else {
- layer->setFilter(GL_LINEAR);
- setupDrawModelView(kModelViewMode_Translate, false,
- rect.left, rect.top, rect.right, rect.bottom);
- }
- setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
+ layer->setFilter(GL_NEAREST);
+ setupDrawModelView(kModelViewMode_Translate, false,
+ x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR);
+ setupDrawModelView(kModelViewMode_Translate, false,
+ rect.left, rect.top, rect.right, rect.bottom);
+ }
+ setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
- for (size_t i = 0; i < count; i++) {
- const android::Rect* r = &rects[i];
+ for (size_t i = 0; i < count; i++) {
+ const android::Rect* r = &rects[i];
- const float u1 = r->left * texX;
- const float v1 = (height - r->top) * texY;
- const float u2 = r->right * texX;
- const float v2 = (height - r->bottom) * texY;
+ const float u1 = r->left * texX;
+ const float v1 = (height - r->top) * texY;
+ const float u2 = r->right * texX;
+ const float v2 = (height - r->bottom) * texY;
- // TODO: Reject quads outside of the clip
- TextureVertex::set(mesh++, r->left, r->top, u1, v1);
- TextureVertex::set(mesh++, r->right, r->top, u2, v1);
- TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
- TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+ // TODO: Reject quads outside of the clip
+ TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+ TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+ TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+ TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
- numQuads++;
+ numQuads++;
- if (numQuads >= gMaxNumberOfQuads) {
- DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
- GL_UNSIGNED_SHORT, NULL));
- numQuads = 0;
- mesh = mCaches.getRegionMesh();
- }
- }
-
- if (numQuads > 0) {
+ if (numQuads >= gMaxNumberOfQuads) {
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
GL_UNSIGNED_SHORT, NULL));
+ numQuads = 0;
+ mesh = mCaches.getRegionMesh();
}
+ }
+
+ if (numQuads > 0) {
+ DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
+ GL_UNSIGNED_SHORT, NULL));
+ }
#if DEBUG_LAYERS_AS_REGIONS
- drawRegionRectsDebug(layer->region);
+ drawRegionRectsDebug(layer->region);
#endif
- layer->region.clear();
- }
+ layer->region.clear();
}
#if DEBUG_LAYERS_AS_REGIONS
@@ -2926,7 +2958,7 @@
if (layer->isTextureLayer()) {
transform = &layer->getTransform();
if (!transform->isIdentity()) {
- save(0);
+ save(SkCanvas::kMatrix_SaveFlag);
concatMatrix(*transform);
}
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 2debd2e..b49d1e1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -161,7 +161,14 @@
ANDROID_API void flushLayerUpdates();
ANDROID_API virtual int saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags);
+ const SkPaint* paint, int flags) {
+ return saveLayer(left, top, right, bottom, paint, flags, NULL);
+ }
+
+ // Specialized saveLayer implementation, which will pass the convexMask to an FBO layer, if
+ // created, which will in turn clip to that mask when drawn back/restored.
+ int saveLayer(float left, float top, float right, float bottom,
+ const SkPaint* paint, int flags, const SkPath* convexMask);
int saveLayerDeferred(float left, float top, float right, float bottom,
const SkPaint* paint, int flags);
@@ -523,11 +530,12 @@
* @param alpha The translucency of the layer
* @param mode The blending mode of the layer
* @param flags The layer save flags
+ * @param mask A mask to use when drawing the layer back, may be empty
*
* @return True if the layer was successfully created, false otherwise
*/
bool createLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags);
+ const SkPaint* paint, int flags, const SkPath* convexMask);
/**
* Creates a new layer stored in the specified snapshot as an FBO.
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 0083b77..92964a8 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -30,6 +30,8 @@
#define RECT_STRING "%7.2f %7.2f %7.2f %7.2f"
#define RECT_ARGS(r) \
(r).left, (r).top, (r).right, (r).bottom
+#define SK_RECT_ARGS(r) \
+ (r).left(), (r).top(), (r).right(), (r).bottom()
///////////////////////////////////////////////////////////////////////////////
// Structs
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 9aa47a3..838e5ac 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -77,7 +77,7 @@
*/
void RenderNode::output(uint32_t level) {
ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
- mName.string(), isRenderable());
+ getName(), isRenderable());
ALOGD("%*s%s %d", level * 2, "", "Save",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -87,7 +87,7 @@
mDisplayListData->displayListOps[i]->output(level, flags);
}
- ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
+ ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
}
void RenderNode::prepareTree(TreeInfo& info) {
@@ -219,11 +219,11 @@
matrix.multiply(anim);
}
- bool applyTranslationZ = true3dTransform && !MathUtils::isZero(properties().getTranslationZ());
+ bool applyTranslationZ = true3dTransform && !MathUtils::isZero(properties().getZ());
if (properties().hasTransformMatrix() || applyTranslationZ) {
if (properties().isTransformTranslateOnly()) {
matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
- true3dTransform ? properties().getTranslationZ() : 0.0f);
+ true3dTransform ? properties().getZ() : 0.0f);
} else {
if (!true3dTransform) {
matrix.multiply(*properties().getTransformMatrix());
@@ -232,7 +232,7 @@
true3dMat.loadTranslate(
properties().getPivotX() + properties().getTranslationX(),
properties().getPivotY() + properties().getTranslationY(),
- properties().getTranslationZ());
+ properties().getZ());
true3dMat.rotate(properties().getRotationX(), 1, 0, 0);
true3dMat.rotate(properties().getRotationY(), 0, 1, 0);
true3dMat.rotate(properties().getRotation(), 0, 0, 1);
@@ -263,12 +263,13 @@
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children()[i];
childOp->mDisplayList->computeOrderingImpl(childOp,
- &mProjectedNodes, &mat4::identity());
+ properties().getOutline().getPath(), &mProjectedNodes, &mat4::identity());
}
}
void RenderNode::computeOrderingImpl(
DrawDisplayListOp* opState,
+ const SkPath* outlineOfProjectionSurface,
Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface) {
mProjectedNodes.clear();
@@ -296,6 +297,7 @@
DrawDisplayListOp* childOp = mDisplayListData->children()[i];
RenderNode* child = childOp->mDisplayList;
+ const SkPath* projectionOutline = NULL;
Vector<DrawDisplayListOp*>* projectionChildren = NULL;
const mat4* projectionTransform = NULL;
if (isProjectionReceiver && !child->properties().getProjectBackwards()) {
@@ -304,6 +306,7 @@
// Note that if a direct descendent is projecting backwards, we pass it's
// grandparent projection collection, since it shouldn't project onto it's
// parent, where it will already be drawing.
+ projectionOutline = properties().getOutline().getPath();
projectionChildren = &mProjectedNodes;
projectionTransform = &mat4::identity();
} else {
@@ -311,10 +314,12 @@
applyViewPropertyTransforms(localTransformFromProjectionSurface);
haveAppliedPropertiesToProjection = true;
}
+ projectionOutline = outlineOfProjectionSurface;
projectionChildren = compositedChildrenOfProjectionSurface;
projectionTransform = &localTransformFromProjectionSurface;
}
- child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
+ child->computeOrderingImpl(childOp,
+ projectionOutline, projectionChildren, projectionTransform);
}
}
}
@@ -339,7 +344,9 @@
void RenderNode::deferNodeTree(DeferStateStruct& deferStruct) {
DeferOperationHandler handler(deferStruct, 0);
- if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
+ if (MathUtils::isPositive(properties().getZ())) {
+ issueDrawShadowOperation(Matrix4::identity(), handler);
+ }
issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
}
@@ -354,7 +361,7 @@
: mReplayStruct(replayStruct), mLevel(level) {}
inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
- properties().getReplayStruct().mRenderer.eventMark(operation->name());
+ mReplayStruct.mRenderer.eventMark(operation->name());
#endif
operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
}
@@ -364,8 +371,6 @@
}
inline void endMark() {
mReplayStruct.mRenderer.endMark();
- DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
- mReplayStruct.mDrawGlStatus);
}
inline int level() { return mLevel; }
inline int replayFlags() { return mReplayStruct.mReplayFlags; }
@@ -377,7 +382,9 @@
void RenderNode::replayNodeTree(ReplayStateStruct& replayStruct) {
ReplayOperationHandler handler(replayStruct, 0);
- if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
+ if (MathUtils::isPositive(properties().getZ())) {
+ issueDrawShadowOperation(Matrix4::identity(), handler);
+ }
issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
}
@@ -392,7 +399,7 @@
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children()[i];
RenderNode* child = childOp->mDisplayList;
- float childZ = child->properties().getTranslationZ();
+ float childZ = child->properties().getZ();
if (!MathUtils::isZero(childZ)) {
zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp));
@@ -470,6 +477,10 @@
endIndex = size;
shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
}
+
+ DISPLAY_LIST_LOGD("%*s%d %s 3d children:", (handler.level() + 1) * 2, "",
+ endIndex - drawIndex, mode == kNegativeZChildren ? "negative" : "positive");
+
float lastCasterZ = 0.0f;
while (shadowIndex < endIndex || drawIndex < endIndex) {
if (shadowIndex < endIndex) {
@@ -506,6 +517,42 @@
template <class T>
void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
+ DISPLAY_LIST_LOGD("%*s%d projected children:", (handler.level() + 1) * 2, "", mProjectedNodes.size());
+ const SkPath* projectionReceiverOutline = properties().getOutline().getPath();
+ bool maskProjecteesWithPath = projectionReceiverOutline != NULL
+ && !projectionReceiverOutline->isRect(NULL);
+ int restoreTo = renderer.getSaveCount();
+
+ // If the projection reciever has an outline, we mask each of the projected rendernodes to it
+ // Either with clipRect, or special saveLayer masking
+ LinearAllocator& alloc = handler.allocator();
+ if (projectionReceiverOutline != NULL) {
+ const SkRect& outlineBounds = projectionReceiverOutline->getBounds();
+ if (projectionReceiverOutline->isRect(NULL)) {
+ // mask to the rect outline simply with clipRect
+ handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+ PROPERTY_SAVECOUNT, properties().getClipToBounds());
+ ClipRectOp* clipOp = new (alloc) ClipRectOp(
+ outlineBounds.left(), outlineBounds.top(),
+ outlineBounds.right(), outlineBounds.bottom(), SkRegion::kIntersect_Op);
+ handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+ } else {
+ // wrap the projected RenderNodes with a SaveLayer that will mask to the outline
+ SaveLayerOp* op = new (alloc) SaveLayerOp(
+ outlineBounds.left(), outlineBounds.top(),
+ outlineBounds.right(), outlineBounds.bottom(),
+ 255, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ op->setMask(projectionReceiverOutline);
+ handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+
+ /* TODO: add optimizations here to take advantage of placement/size of projected
+ * children (which may shrink saveLayer area significantly). This is dependent on
+ * passing actual drawing/dirtying bounds of projected content down to native.
+ */
+ }
+ }
+
+ // draw projected nodes
for (size_t i = 0; i < mProjectedNodes.size(); i++) {
DrawDisplayListOp* childOp = mProjectedNodes[i];
@@ -517,6 +564,11 @@
childOp->mSkipInOrderDraw = true;
renderer.restoreToCount(restoreTo);
}
+
+ if (projectionReceiverOutline != NULL) {
+ handler(new (alloc) RestoreToCountOp(restoreTo),
+ PROPERTY_SAVECOUNT, properties().getClipToBounds());
+ }
}
/**
@@ -532,17 +584,17 @@
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
const int level = handler.level();
if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
- DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
+ DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
return;
}
- handler.startMark(mName.string());
+ handler.startMark(getName());
#if DEBUG_DISPLAY_LIST
- Rect* clipRect = renderer.getClipRect();
- DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
- level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
- clipRect->right, clipRect->bottom);
+ const Rect& clipRect = renderer.getLocalClipBounds();
+ DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f",
+ level * 2, "", this, getName(),
+ clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
#endif
LinearAllocator& alloc = handler.allocator();
@@ -590,6 +642,7 @@
PROPERTY_SAVECOUNT, properties().getClipToBounds());
renderer.setOverrideLayerAlpha(1.0f);
+ DISPLAY_LIST_LOGD("%*sDone (%p, %s)", level * 2, "", this, getName());
handler.endMark();
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 6688952..b9edbe5 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -172,6 +172,7 @@
void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false);
void computeOrderingImpl(DrawDisplayListOp* opState,
+ const SkPath* outlineOfProjectionSurface,
Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface);
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index a922db8..9ec7297 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -37,6 +37,7 @@
, mProjectionReceiver(false)
, mAlpha(1)
, mHasOverlappingRendering(true)
+ , mElevation(0)
, mTranslationX(0), mTranslationY(0), mTranslationZ(0)
, mRotation(0), mRotationX(0), mRotationY(0)
, mScaleX(1), mScaleY(1)
@@ -100,7 +101,7 @@
if (hasTransformMatrix()) {
if (isTransformTranslateOnly()) {
ALOGD("%*sTranslate %.2f, %.2f, %.2f",
- level * 2, "", mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY, mPrimitiveFields.mTranslationZ);
+ level * 2, "", getTranslationX(), getTranslationY(), getZ());
} else {
ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 4270da2..8fc2dd0 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -105,6 +105,17 @@
return mPrimitiveFields.mHasOverlappingRendering;
}
+ void setElevation(float elevation) {
+ if (elevation != mPrimitiveFields.mElevation) {
+ mPrimitiveFields.mElevation = elevation;
+ // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
+ }
+ }
+
+ float getElevation() const {
+ return mPrimitiveFields.mElevation;
+ }
+
void setTranslationX(float translationX) {
if (translationX != mPrimitiveFields.mTranslationX) {
mPrimitiveFields.mTranslationX = translationX;
@@ -130,7 +141,7 @@
void setTranslationZ(float translationZ) {
if (translationZ != mPrimitiveFields.mTranslationZ) {
mPrimitiveFields.mTranslationZ = translationZ;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
+ // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
}
}
@@ -138,6 +149,10 @@
return mPrimitiveFields.mTranslationZ;
}
+ float getZ() const {
+ return getElevation() + getTranslationZ();
+ }
+
void setRotation(float rotation) {
if (rotation != mPrimitiveFields.mRotation) {
mPrimitiveFields.mRotation = rotation;
@@ -302,7 +317,8 @@
}
void setLeftTopRightBottom(int left, int top, int right, int bottom) {
- if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
+ if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop
+ || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
mPrimitiveFields.mLeft = left;
mPrimitiveFields.mTop = top;
mPrimitiveFields.mRight = right;
@@ -429,6 +445,7 @@
bool mProjectionReceiver;
float mAlpha;
bool mHasOverlappingRendering;
+ float mElevation;
float mTranslationX, mTranslationY, mTranslationZ;
float mRotation, mRotationX, mRotationY;
float mScaleX, mScaleY;
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index efcea5f..3209a53 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -167,7 +167,7 @@
virtual void concatMatrix(const SkMatrix* matrix) = 0;
// clip
- virtual const Rect& getClipBounds() const = 0;
+ virtual const Rect& getLocalClipBounds() const = 0;
virtual bool quickRejectConservative(float left, float top,
float right, float bottom) const = 0;
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 4f2a432..6a4a0c8 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -73,7 +73,7 @@
}
SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
- SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
+ SkShader::TileMode tileY, const SkMatrix* matrix, bool blend):
mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend),
mCaches(NULL) {
setMatrix(matrix);
@@ -101,6 +101,49 @@
}
///////////////////////////////////////////////////////////////////////////////
+// Layer shader
+///////////////////////////////////////////////////////////////////////////////
+
+SkiaLayerShader::SkiaLayerShader(Layer* layer, const SkMatrix* matrix):
+ SkiaShader(kBitmap, NULL, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
+ matrix, layer->isBlend()), mLayer(layer) {
+ updateLocalMatrix(matrix);
+}
+
+SkiaShader* SkiaLayerShader::copy() {
+ SkiaLayerShader* copy = new SkiaLayerShader();
+ copy->copyFrom(*this);
+ copy->mLayer = mLayer;
+ return copy;
+}
+
+void SkiaLayerShader::describe(ProgramDescription& description, const Extensions& extensions) {
+ description.hasBitmap = true;
+}
+
+void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView,
+ const Snapshot& snapshot, GLuint* textureUnit) {
+ GLuint textureSlot = (*textureUnit)++;
+ Caches::getInstance().activeTexture(textureSlot);
+
+ const float width = mLayer->getWidth();
+ const float height = mLayer->getHeight();
+
+ mat4 textureTransform;
+ computeScreenSpaceMatrix(textureTransform, modelView);
+
+ // Uniforms
+ mLayer->bindTexture();
+ mLayer->setWrap(GL_CLAMP_TO_EDGE);
+ mLayer->setFilter(GL_LINEAR);
+
+ glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
+ glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+ GL_FALSE, &textureTransform.data[0]);
+ glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Bitmap shader
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 6015761..9f30257 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -58,7 +58,7 @@
};
ANDROID_API SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
- SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
+ SkShader::TileMode tileY, const SkMatrix* matrix, bool blend);
virtual ~SkiaShader();
virtual SkiaShader* copy() = 0;
@@ -88,7 +88,7 @@
return mGenerationId;
}
- void setMatrix(SkMatrix* matrix) {
+ void setMatrix(const SkMatrix* matrix) {
updateLocalMatrix(matrix);
mGenerationId++;
}
@@ -134,6 +134,24 @@
///////////////////////////////////////////////////////////////////////////////
/**
+ * A shader that draws a layer.
+ */
+struct SkiaLayerShader: public SkiaShader {
+ SkiaLayerShader(Layer* layer, const SkMatrix* matrix);
+ SkiaShader* copy();
+
+ void describe(ProgramDescription& description, const Extensions& extensions);
+ void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
+ GLuint* textureUnit);
+
+private:
+ SkiaLayerShader() {
+ }
+
+ Layer* mLayer;
+}; // struct SkiaLayerShader
+
+/**
* A shader that draws a bitmap.
*/
struct SkiaBitmapShader: public SkiaShader {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 5bdb18a..038aea8 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -108,7 +108,12 @@
* Returns the current clip in local coordinates. The clip rect is
* transformed by the inverse transform matrix.
*/
- ANDROID_API const Rect& getLocalClip();
+ const Rect& getLocalClip();
+
+ /**
+ * Returns the current clip in render target coordinates.
+ */
+ const Rect& getRenderTargetClip() { return *clipRect; }
/**
* Resets the clip to the specified rect.
@@ -238,7 +243,7 @@
mat4 mTransformRoot;
Rect mClipRectRoot;
- Rect mLocalClip;
+ Rect mLocalClip; // don't use directly, call getLocalClip() which initializes this
SkRegion mClipRegionRoot;
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index bf34bec..64354ac 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -75,7 +75,8 @@
void concatMatrix(const Matrix4& matrix); // internal only convenience method
// Clip
- const Rect& getClipBounds() const { return mSnapshot->getLocalClip(); }
+ virtual const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
+
virtual bool quickRejectConservative(float left, float top, float right, float bottom) const;
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
@@ -83,6 +84,8 @@
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
protected:
+ const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
+
int getWidth() { return mWidth; }
int getHeight() { return mHeight; }
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 57ba8fa..7deabe9 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -29,6 +29,10 @@
inline static bool isZero(float value) {
return (value >= -gNonZeroEpsilon) && (value <= gNonZeroEpsilon);
}
+
+ inline static bool isPositive(float value) {
+ return value >= gNonZeroEpsilon;
+ }
}; // class MathUtils
} /* namespace uirenderer */
diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java
index 623d707..5600aeb 100644
--- a/location/java/android/location/FusedBatchOptions.java
+++ b/location/java/android/location/FusedBatchOptions.java
@@ -95,8 +95,9 @@
}
public static final class BatchFlags {
- public static int WAKEUP_ON_FIFO_FULL = 1<<0;
- public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+ // follow the definitions to the letter in fused_location.h
+ public static int WAKEUP_ON_FIFO_FULL = 0x0000001;
+ public static int CALLBACK_ON_LOCATION_FIX =0x0000002;
}
/*
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 04c6e97..ad0d459 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -88,12 +88,22 @@
public static final int CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT;
public static final int CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT);
+ // aka QUAD_BACK
public static final int CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
+ /** @hide */
+ public static final int CHANNEL_OUT_QUAD_SIDE = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT);
public static final int CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER);
+ // aka 5POINT1_BACK
public static final int CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
+ /** @hide */
+ public static final int CHANNEL_OUT_5POINT1_SIDE = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY |
+ CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT);
+ // TODO does this need an @deprecated ?
// different from AUDIO_CHANNEL_OUT_7POINT1
public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
diff --git a/media/java/android/media/DngCreator.java b/media/java/android/media/DngCreator.java
new file mode 100644
index 0000000..b2a38ab
--- /dev/null
+++ b/media/java/android/media/DngCreator.java
@@ -0,0 +1,254 @@
+/*
+ * 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;
+
+import android.graphics.Bitmap;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureResult;
+import android.location.Location;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * The {@link DngCreator} class provides functions to write raw pixel data as a DNG file.
+ *
+ * <p>
+ * This class is designed to be used with the {@link android.graphics.ImageFormat#RAW_SENSOR}
+ * buffers available from {@link android.hardware.camera2.CameraDevice}, or with Bayer-type raw
+ * pixel data that is otherwise generated by an application. The DNG metadata tags will be
+ * generated from a {@link android.hardware.camera2.CaptureResult} object or set directly.
+ * </p>
+ *
+ * <p>
+ * The DNG file format is a cross-platform file format that is used to store pixel data from
+ * camera sensors with minimal pre-processing applied. DNG files allow for pixel data to be
+ * defined in a user-defined colorspace, and have associated metadata that allow for this
+ * pixel data to be converted to the standard CIE XYZ colorspace during post-processing.
+ * </p>
+ *
+ * <p>
+ * For more information on the DNG file format and associated metadata, please refer to the
+ * <a href=
+ * "https://wwwimages2.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf">
+ * Adobe DNG 1.4.0.0 specification</a>.
+ * </p>
+ */
+public final class DngCreator {
+
+ /**
+ * Create a new DNG object.
+ *
+ * <p>
+ * It is not necessary to call any set methods to write a well-formatted DNG file.
+ * </p>
+ * <p>
+ * DNG metadata tags will be generated from the corresponding parameters in the
+ * {@link android.hardware.camera2.CaptureResult} object. This removes or overrides
+ * all previous tags set.
+ * </p>
+ *
+ * @param characteristics an object containing the static
+ * {@link android.hardware.camera2.CameraCharacteristics}.
+ * @param metadata a metadata object to generate tags from.
+ */
+ public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {/*TODO*/}
+
+ /**
+ * Set the orientation value to write.
+ *
+ * <p>
+ * This will be written as the TIFF "Orientation" tag {@code (0x0112)}.
+ * Calling this will override any prior settings for this tag.
+ * </p>
+ *
+ * @param orientation the orientation value to set, one of:
+ * <ul>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_NORMAL}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_FLIP_HORIZONTAL}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_180}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_FLIP_VERTICAL}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_TRANSPOSE}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_90}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_TRANSVERSE}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_270}</li>
+ * </ul>
+ * @return this {@link #DngCreator} object.
+ */
+ public DngCreator setOrientation(int orientation) {
+ return this;
+ }
+
+ /**
+ * Set the thumbnail image.
+ *
+ * <p>
+ * Pixel data will be converted to a Baseline TIFF RGB image, with 8 bits per color channel.
+ * The alpha channel will be discarded.
+ * </p>
+ *
+ * <p>
+ * The given bitmap should not be altered while this object is in use.
+ * </p>
+ *
+ * @param pixels a {@link android.graphics.Bitmap} of pixel data.
+ * @return this {@link #DngCreator} object.
+ */
+ public DngCreator setThumbnail(Bitmap pixels) {
+ return this;
+ }
+
+ /**
+ * Set the thumbnail image.
+ *
+ * <p>
+ * Pixel data is interpreted as a {@link android.graphics.ImageFormat#YUV_420_888} image.
+ * </p>
+ *
+ * <p>
+ * The given image should not be altered while this object is in use.
+ * </p>
+ *
+ * @param pixels an {@link android.media.Image} object with the format
+ * {@link android.graphics.ImageFormat#YUV_420_888}.
+ * @return this {@link #DngCreator} object.
+ */
+ public DngCreator setThumbnail(Image pixels) {
+ return this;
+ }
+
+
+ /**
+ * Set image location metadata.
+ *
+ * <p>
+ * The given location object must contain at least a valid time, latitude, and longitude
+ * (equivalent to the values returned by {@link android.location.Location#getTime()},
+ * {@link android.location.Location#getLatitude()}, and
+ * {@link android.location.Location#getLongitude()} methods).
+ * </p>
+ *
+ * @param location an {@link android.location.Location} object to set.
+ * @return this {@link #DngCreator} object.
+ *
+ * @throws java.lang.IllegalArgumentException if the given location object doesn't
+ * contain enough information to set location metadata.
+ */
+ public DngCreator setLocation(Location location) { return this; }
+
+ /**
+ * Set the user description string to write.
+ *
+ * <p>
+ * This is equivalent to setting the TIFF "ImageDescription" tag {@code (0x010E)}.
+ * </p>
+ *
+ * @param description the user description string.
+ * @return this {@link #DngCreator} object.
+ */
+ public DngCreator setDescription(String description) {
+ return this;
+ }
+
+ /**
+ * Write the {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data to a DNG file with
+ * the currently configured metadata.
+ *
+ * <p>
+ * Raw pixel data must have 16 bits per pixel, and the input must contain at least
+ * {@code offset + 2 * (stride * (height - 1) + width * height)} bytes. The width and height of
+ * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
+ * and will typically be equal to the width and height of
+ * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+ * If insufficient metadata is set to write a well-formatted DNG file, and
+ * {@link java.lang.IllegalStateException} will be thrown.
+ * </p>
+ *
+ * <p>
+ * When reading from the pixel input, {@code stride} pixels will be skipped
+ * after each row (excluding the last).
+ * </p>
+ *
+ * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+ * @param pixels an {@link java.io.InputStream} of pixel data to write.
+ * @param stride the stride of the raw image in pixels.
+ * @param offset the offset of the raw image in bytes. This indicates how many bytes will
+ * be skipped in the input before any pixel data is read.
+ *
+ * @throws IOException if an error was encountered in the input or output stream.
+ * @throws java.lang.IllegalStateException if not enough metadata information has been
+ * set to write a well-formatted DNG file.
+ */
+ public void writeInputStream(OutputStream dngOutput, InputStream pixels, int stride,
+ long offset) throws IOException {
+ /*TODO*/
+ }
+
+ /**
+ * Write the {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data to a DNG file with
+ * the currently configured metadata.
+ *
+ * <p>
+ * Raw pixel data must have 16 bits per pixel, and the input must contain at least
+ * {@code offset + 2 * (stride * (height - 1) + width * height)} bytes. The width and height of
+ * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
+ * and will typically be equal to the width and height of
+ * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+ * If insufficient metadata is set to write a well-formatted DNG file, and
+ * {@link java.lang.IllegalStateException} will be thrown.
+ * </p>
+ *
+ * <p>
+ * When reading from the pixel input, {@code stride} pixels will be skipped
+ * after each row (excluding the last).
+ * </p>
+ *
+ * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+ * @param pixels an {@link java.nio.ByteBuffer} of pixel data to write.
+ * @param stride the stride of the raw image in pixels.
+ * @param offset the offset of the raw image in bytes. This indicates how many bytes will
+ * be skipped in the input before any pixel data is read.
+ *
+ * @throws IOException if an error was encountered in the input or output stream.
+ * @throws java.lang.IllegalStateException if not enough metadata information has been
+ * set to write a well-formatted DNG file.
+ */
+ public void writeByteBuffer(OutputStream dngOutput, ByteBuffer pixels, int stride,
+ long offset) throws IOException {/*TODO*/}
+
+ /**
+ * Write the pixel data to a DNG file with the currently configured metadata.
+ *
+ * <p>
+ * For this method to succeed, the {@link android.media.Image} input must contain
+ * {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data, otherwise an
+ * {@link java.lang.IllegalArgumentException} will be thrown.
+ * </p>
+ *
+ * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+ * @param pixels an {@link android.media.Image} to write.
+ *
+ * @throws java.io.IOException if an error was encountered in the output stream.
+ * @throws java.lang.IllegalArgumentException if an image with an unsupported format was used.
+ * @throws java.lang.IllegalStateException if not enough metadata information has been
+ * set to write a well-formatted DNG file.
+ */
+ public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {/*TODO*/}
+
+}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 72f3e1a..9516bf8 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -44,6 +44,8 @@
import android.sax.Element;
import android.sax.ElementListener;
import android.sax.RootElement;
+import android.system.ErrnoException;
+import android.system.Os;
import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
@@ -60,9 +62,6 @@
import java.util.Iterator;
import java.util.Locale;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-
/**
* Internal service helper that no-one should use directly.
*
@@ -1130,7 +1129,7 @@
if (path != null && path.startsWith("/")) {
boolean exists = false;
try {
- exists = Libcore.os.access(path, libcore.io.OsConstants.F_OK);
+ exists = Os.access(path, android.system.OsConstants.F_OK);
} catch (ErrnoException e1) {
}
if (!exists && !MtpConstants.isAbstractObject(format)) {
@@ -1281,6 +1280,14 @@
mMediaProvider = null;
}
+ private void releaseResources() {
+ // release the DrmManagerClient resources
+ if (mDrmManagerClient != null) {
+ mDrmManagerClient.release();
+ mDrmManagerClient = null;
+ }
+ }
+
private void initialize(String volumeName) {
mMediaProvider = mContext.getContentResolver().acquireProvider("media");
@@ -1341,6 +1348,8 @@
Log.e(TAG, "UnsupportedOperationException in MediaScanner.scan()", e);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scan()", e);
+ } finally {
+ releaseResources();
}
}
@@ -1364,6 +1373,8 @@
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
return null;
+ } finally {
+ releaseResources();
}
}
@@ -1511,6 +1522,7 @@
if (fileList != null) {
fileList.close();
}
+ releaseResources();
}
}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 716418c..7a86811 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -274,17 +274,11 @@
fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I");
jpegFormat = env->GetStaticIntField(imageFormatClazz, fid);
- fid = env->GetStaticFieldID(imageFormatClazz, "RAW_SENSOR", "I");
- rawSensorFormat = env->GetStaticIntField(imageFormatClazz, fid);
- // Translate the JPEG to BLOB for camera purpose, an add more if more mismatch is found.
+ // Translate the JPEG to BLOB for camera purpose.
if (format == jpegFormat) {
format = HAL_PIXEL_FORMAT_BLOB;
}
- // Same thing for RAW_SENSOR format
- if (format == rawSensorFormat) {
- format = HAL_PIXEL_FORMAT_RAW_SENSOR;
- }
return format;
}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index fb4de9e..acfcd83 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -123,10 +123,13 @@
ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue,
ASensorEvent* events, size_t count)
{
- return static_cast<SensorEventQueue*>(queue)->read(events, count);
+ ssize_t actual = static_cast<SensorEventQueue*>(queue)->read(events, count);
+ if (actual > 0) {
+ static_cast<SensorEventQueue*>(queue)->sendAck(events, actual);
+ }
+ return actual;
}
-
/*****************************************************************************/
const char* ASensor_getName(ASensor const* sensor)
diff --git a/packages/DefaultContainerService/res/values-th/strings.xml b/packages/DefaultContainerService/res/values-th/strings.xml
index 3a7080c..621d7ed 100644
--- a/packages/DefaultContainerService/res/values-th/strings.xml
+++ b/packages/DefaultContainerService/res/values-th/strings.xml
@@ -20,5 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="service_name" msgid="4841491635055379553">"ตัวช่วยเหลือของการเข้าถึงแพคเกจ"</string>
+ <string name="service_name" msgid="4841491635055379553">"ตัวช่วยเหลือของการเข้าถึงแพ็กเกจ"</string>
</resources>
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 48ef9db..36c1d5c 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -41,6 +41,9 @@
import android.os.ServiceManager;
import android.os.StatFs;
import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStatVfs;
import android.util.DisplayMetrics;
import android.util.Slog;
@@ -66,11 +69,8 @@
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import libcore.io.Streams;
-import libcore.io.StructStatVfs;
/*
* This service copies a downloaded apk to a file passed in as
@@ -245,7 +245,7 @@
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
try {
- final StructStatVfs stat = Libcore.os.statvfs(path);
+ final StructStatVfs stat = Os.statvfs(path);
final long totalSize = stat.f_blocks * stat.f_bsize;
final long availSize = stat.f_bavail * stat.f_bsize;
return new long[] { totalSize, availSize };
@@ -379,7 +379,7 @@
}
try {
- Libcore.os.chmod(resFile.getAbsolutePath(), 0640);
+ Os.chmod(resFile.getAbsolutePath(), 0640);
} catch (ErrnoException e) {
Slog.e(TAG, "Could not chown APK: " + e.getMessage());
PackageHelper.destroySdDir(newCid);
@@ -401,7 +401,7 @@
}
try {
- Libcore.os.chmod(publicZipFile.getAbsolutePath(), 0644);
+ Os.chmod(publicZipFile.getAbsolutePath(), 0644);
} catch (ErrnoException e) {
Slog.e(TAG, "Could not chown public resource file: " + e.getMessage());
PackageHelper.destroySdDir(newCid);
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 41fd63a..65dbe18 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Stoor"</string>
<string name="menu_share" msgid="3075149983979628146">"Deel"</string>
<string name="menu_delete" msgid="8138799623850614177">"Vee uit"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> gekies"</string>
<string name="sort_name" msgid="9183560467917256779">"Volgens naam"</string>
<string name="sort_date" msgid="586080032956151448">"Volgens datum gewysig"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index c77a8ee..1003c0a 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"አስቀምጥ"</string>
<string name="menu_share" msgid="3075149983979628146">"አጋራ"</string>
<string name="menu_delete" msgid="8138799623850614177">"ሰርዝ"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ተመርጠዋል"</string>
<string name="sort_name" msgid="9183560467917256779">"በስም"</string>
<string name="sort_date" msgid="586080032956151448">"በተለወጠበት ቀን"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index c59c0ee..e939b3e 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"حفظ"</string>
<string name="menu_share" msgid="3075149983979628146">"مشاركة"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"تم تحديد <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string>
<string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index c3242b2..18cdb9c 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Запазване"</string>
<string name="menu_share" msgid="3075149983979628146">"Споделяне"</string>
<string name="menu_delete" msgid="8138799623850614177">"Изтриване"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Избрахте <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"По име"</string>
<string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 68c7b0e..b883869 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Desa"</string>
<string name="menu_share" msgid="3075149983979628146">"Comparteix"</string>
<string name="menu_delete" msgid="8138799623850614177">"Suprimeix"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Seleccionats: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Per nom"</string>
<string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index f089c8b..3827b94 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Uložit"</string>
<string name="menu_share" msgid="3075149983979628146">"Sdílet"</string>
<string name="menu_delete" msgid="8138799623850614177">"Smazat"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Vybráno: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string>
<string name="sort_date" msgid="586080032956151448">"Podle data úpravy"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 816f9a7..25c74e3 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Gem"</string>
<string name="menu_share" msgid="3075149983979628146">"Del"</string>
<string name="menu_delete" msgid="8138799623850614177">"Slet"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> er valgt"</string>
<string name="sort_name" msgid="9183560467917256779">"Efter navn"</string>
<string name="sort_date" msgid="586080032956151448">"Efter ændringsdato"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index e43a1e2..93fad32 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Speichern"</string>
<string name="menu_share" msgid="3075149983979628146">"Teilen"</string>
<string name="menu_delete" msgid="8138799623850614177">"Löschen"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ausgewählt"</string>
<string name="sort_name" msgid="9183560467917256779">"Nach Name"</string>
<string name="sort_date" msgid="586080032956151448">"Nach Änderungsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 5a91484..db83aea 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Αποθήκευση"</string>
<string name="menu_share" msgid="3075149983979628146">"Κοινοποίηση"</string>
<string name="menu_delete" msgid="8138799623850614177">"Διαγραφή"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Επιλέχθηκαν <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Κατά όνομα"</string>
<string name="sort_date" msgid="586080032956151448">"Κατά ημερομηνία τροποποίησης"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index a95e7f1..a0fe3b7 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Save"</string>
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index a95e7f1..a0fe3b7 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Save"</string>
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 4a3ff33..3319011 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> seleccionado(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 1682542..7189f1d 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Seleccionado: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 5412956..a12b695 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Salvesta"</string>
<string name="menu_share" msgid="3075149983979628146">"Jaga"</string>
<string name="menu_delete" msgid="8138799623850614177">"Kustuta"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> on valitud"</string>
<string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string>
<string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index c922b37..ba04522 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"ذخیره"</string>
<string name="menu_share" msgid="3075149983979628146">"اشتراکگذاری"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> انتخاب شد"</string>
<string name="sort_name" msgid="9183560467917256779">"بر اساس نام"</string>
<string name="sort_date" msgid="586080032956151448">"بر اساس تاریخ اصلاح"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 5e40ecd..8ea10be 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Tallenna"</string>
<string name="menu_share" msgid="3075149983979628146">"Jaa"</string>
<string name="menu_delete" msgid="8138799623850614177">"Poista"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valittua"</string>
<string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string>
<string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index a837379..0549707 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string>
<string name="menu_share" msgid="3075149983979628146">"Partager"</string>
<string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> sélectionné(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
<string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index ff9aeda..292ec86 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string>
<string name="menu_share" msgid="3075149983979628146">"Partager"</string>
<string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> élément(s) sélectionné(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
<string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 8d7fcba..579bd37 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"सहेजें"</string>
<string name="menu_share" msgid="3075149983979628146">"साझा करें"</string>
<string name="menu_delete" msgid="8138799623850614177">"हटाएं"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> चयनित"</string>
<string name="sort_name" msgid="9183560467917256779">"नाम के अनुसार"</string>
<string name="sort_date" msgid="586080032956151448">"बदलाव के दिनांक के अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 73c2f04..6baae95 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Spremi"</string>
<string name="menu_share" msgid="3075149983979628146">"Dijeli"</string>
<string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Odabrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Po korisniku"</string>
<string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index db7854b..b8ef2d4 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Mentés"</string>
<string name="menu_share" msgid="3075149983979628146">"Megosztás"</string>
<string name="menu_delete" msgid="8138799623850614177">"Törlés"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> kiválasztva"</string>
<string name="sort_name" msgid="9183560467917256779">"Név szerint"</string>
<string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index c683f3e..69fdfb6 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Պահել"</string>
<string name="menu_share" msgid="3075149983979628146">"Համօգտագործել"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ջնջել"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ընտրված"</string>
<string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string>
<string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index d9f4475..d5c69bf 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Simpan"</string>
<string name="menu_share" msgid="3075149983979628146">"Bagikan"</string>
<string name="menu_delete" msgid="8138799623850614177">"Hapus"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string>
<string name="sort_name" msgid="9183560467917256779">"Menurut nama"</string>
<string name="sort_date" msgid="586080032956151448">"Menurut tanggal diubah"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index baca387..9d1fc94 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Salva"</string>
<string name="menu_share" msgid="3075149983979628146">"Condividi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Elimina"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selezionati"</string>
<string name="sort_name" msgid="9183560467917256779">"Per nome"</string>
<string name="sort_date" msgid="586080032956151448">"Per data di modifica"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 712c060..af47c6c 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"שמור"</string>
<string name="menu_share" msgid="3075149983979628146">"שתף"</string>
<string name="menu_delete" msgid="8138799623850614177">"מחק"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> נבחרו"</string>
<string name="sort_name" msgid="9183560467917256779">"לפי שם"</string>
<string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 996496d..ca64914 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"保存"</string>
<string name="menu_share" msgid="3075149983979628146">"共有"</string>
<string name="menu_delete" msgid="8138799623850614177">"削除"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>件選択済み"</string>
<string name="sort_name" msgid="9183560467917256779">"名前順"</string>
<string name="sort_date" msgid="586080032956151448">"更新日順"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index f3e1274..3e3d509 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"შენახვა"</string>
<string name="menu_share" msgid="3075149983979628146">"გაზიარება"</string>
<string name="menu_delete" msgid="8138799623850614177">"წაშლა"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> მონიშნული"</string>
<string name="sort_name" msgid="9183560467917256779">"სახელით"</string>
<string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 80f3698..2ecbba7 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"រក្សាទុក"</string>
<string name="menu_share" msgid="3075149983979628146">"ចែករំលែក"</string>
<string name="menu_delete" msgid="8138799623850614177">"លុប"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"បានជ្រើស <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"តាមឈ្មោះ"</string>
<string name="sort_date" msgid="586080032956151448">"តាមកាលបរិច្ឆេទបានកែប្រែ"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 2cd0d44..0ece450 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"저장"</string>
<string name="menu_share" msgid="3075149983979628146">"공유"</string>
<string name="menu_delete" msgid="8138799623850614177">"삭제"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>개 선택됨"</string>
<string name="sort_name" msgid="9183560467917256779">"이름순"</string>
<string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 9a6f32f..0bc0b8b 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"ບັນທຶກ"</string>
<string name="menu_share" msgid="3075149983979628146">"ແບ່ງປັນ"</string>
<string name="menu_delete" msgid="8138799623850614177">"ລຶບ"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"ເລືອກແລ້ວ <xliff:g id="COUNT">%1$d</xliff:g> ລາຍການ"</string>
<string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string>
<string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index f861b99..04825f9 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Išsaugoti"</string>
<string name="menu_share" msgid="3075149983979628146">"Bendrinti"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ištrinti"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Pasirinkta: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string>
<string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 651a59fe0d..5157327 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Saglabāt"</string>
<string name="menu_share" msgid="3075149983979628146">"Kopīgot"</string>
<string name="menu_delete" msgid="8138799623850614177">"Dzēst"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Atlasīts: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string>
<string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 22c9fcd..8fd8f52 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Хадгалах"</string>
<string name="menu_share" msgid="3075149983979628146">"Хуваалцах"</string>
<string name="menu_delete" msgid="8138799623850614177">"Устгах"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> сонгогдсон"</string>
<string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string>
<string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 7e09c57..48e30305 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Simpan"</string>
<string name="menu_share" msgid="3075149983979628146">"Kongsi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Padam"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string>
<string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string>
<string name="sort_date" msgid="586080032956151448">"Diubah suai mengikut tarikh"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 8831bd8..09a11d5 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Lagre"</string>
<string name="menu_share" msgid="3075149983979628146">"Del"</string>
<string name="menu_delete" msgid="8138799623850614177">"Slett"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valgt"</string>
<string name="sort_name" msgid="9183560467917256779">"Etter navn"</string>
<string name="sort_date" msgid="586080032956151448">"«Etter dato» endret"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 08862e8..ca626a86 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Opslaan"</string>
<string name="menu_share" msgid="3075149983979628146">"Delen"</string>
<string name="menu_delete" msgid="8138799623850614177">"Verwijderen"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> geselecteerd"</string>
<string name="sort_name" msgid="9183560467917256779">"Op naam"</string>
<string name="sort_date" msgid="586080032956151448">"Op aanpassingsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 42cec9c..7a7978b 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Zapisz"</string>
<string name="menu_share" msgid="3075149983979628146">"Udostępnij"</string>
<string name="menu_delete" msgid="8138799623850614177">"Usuń"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Wybrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
<string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index f1be722..0443c35 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Partilhar"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionado(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 78fcaf8..f9038d1 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Salvar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartilhar"</string>
<string name="menu_delete" msgid="8138799623850614177">"Excluir"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionados"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 5fd44c8..26cd77f 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Salvați"</string>
<string name="menu_share" msgid="3075149983979628146">"Distribuiți"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ștergeți"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selectate"</string>
<string name="sort_name" msgid="9183560467917256779">"După nume"</string>
<string name="sort_date" msgid="586080032956151448">"După data modificării"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 85fd70e0..f8e1f1b 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Сохранить"</string>
<string name="menu_share" msgid="3075149983979628146">"Поделиться"</string>
<string name="menu_delete" msgid="8138799623850614177">"Удалить"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Выбрано: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"По названию"</string>
<string name="sort_date" msgid="586080032956151448">"По дате изменения"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 4b5ebcd..cb4b718 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Uložiť"</string>
<string name="menu_share" msgid="3075149983979628146">"Zdieľať"</string>
<string name="menu_delete" msgid="8138799623850614177">"Odstrániť"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Vybraté: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string>
<string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index f984a0a..a6dc20b 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Shrani"</string>
<string name="menu_share" msgid="3075149983979628146">"Skupna raba"</string>
<string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Št. izbranih: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Po imenu"</string>
<string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index eb0b197..06e0d08 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Сачувај"</string>
<string name="menu_share" msgid="3075149983979628146">"Дели"</string>
<string name="menu_delete" msgid="8138799623850614177">"Избриши"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Изабрано је <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Према имену"</string>
<string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 7aa5c50..da8432e 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Spara"</string>
<string name="menu_share" msgid="3075149983979628146">"Dela"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ta bort"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Har valt <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Efter namn"</string>
<string name="sort_date" msgid="586080032956151448">"Efter ändringsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index 299fda7..c769a59 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Hifadhi"</string>
<string name="menu_share" msgid="3075149983979628146">"Shiriki"</string>
<string name="menu_delete" msgid="8138799623850614177">"Futa"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> zimechaguliwa"</string>
<string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string>
<string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 6ac8810..bf92893 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"บันทึก"</string>
<string name="menu_share" msgid="3075149983979628146">"แชร์"</string>
<string name="menu_delete" msgid="8138799623850614177">"ลบ"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"เลือกไว้ <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string>
<string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index e0fd8c8..bc363e7 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"I-save"</string>
<string name="menu_share" msgid="3075149983979628146">"Ibahagi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Tanggalin"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ang pinili"</string>
<string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string>
<string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 699a5cd..5d7a2be 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Kaydet"</string>
<string name="menu_share" msgid="3075149983979628146">"Paylaş"</string>
<string name="menu_delete" msgid="8138799623850614177">"Sil"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> tane seçildi"</string>
<string name="sort_name" msgid="9183560467917256779">"Ada göre"</string>
<string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index f87b6a2..dbd44b7 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Зберегти"</string>
<string name="menu_share" msgid="3075149983979628146">"Поділитися"</string>
<string name="menu_delete" msgid="8138799623850614177">"Видалити"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Вибрано <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"За назвою"</string>
<string name="sort_date" msgid="586080032956151448">"За датою змінення"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 41e29fa..919708f 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Lưu"</string>
<string name="menu_share" msgid="3075149983979628146">"Chia sẻ"</string>
<string name="menu_delete" msgid="8138799623850614177">"Xóa"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Đã chọn <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Theo tên"</string>
<string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 742cda7..a916b87 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"保存"</string>
<string name="menu_share" msgid="3075149983979628146">"分享"</string>
<string name="menu_delete" msgid="8138799623850614177">"删除"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"已选择<xliff:g id="COUNT">%1$d</xliff:g>项"</string>
<string name="sort_name" msgid="9183560467917256779">"按名称"</string>
<string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 67ed587..7cae910 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"儲存"</string>
<string name="menu_share" msgid="3075149983979628146">"分享"</string>
<string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個"</string>
<string name="sort_name" msgid="9183560467917256779">"按名稱"</string>
<string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 75ecbcf..387fdba 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"儲存"</string>
<string name="menu_share" msgid="3075149983979628146">"共用"</string>
<string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個項目"</string>
<string name="sort_name" msgid="9183560467917256779">"依名稱"</string>
<string name="sort_date" msgid="586080032956151448">"依修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index bedd2cdf..564b2d7 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Londoloza"</string>
<string name="menu_share" msgid="3075149983979628146">"Yabelana"</string>
<string name="menu_delete" msgid="8138799623850614177">"Susa"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> okukhethiwe"</string>
<string name="sort_name" msgid="9183560467917256779">"Ngegama"</string>
<string name="sort_date" msgid="586080032956151448">"Ngedethi yokuguqula"</string>
diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
index b4847f0..b2d0219 100644
--- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
@@ -20,6 +20,7 @@
<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
<com.android.keyguard.EmergencyCarrierArea
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -35,7 +36,8 @@
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/kg_status_line_font_size"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textColor="?android:attr/textColorSecondary"
+ androidprv:allCaps="@bool/kg_use_all_caps" />
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index d12f9bf..bd08eae 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -119,7 +119,7 @@
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (адреса е-поште)"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (имејл адреса)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
diff --git a/packages/Keyguard/res/values/attrs.xml b/packages/Keyguard/res/values/attrs.xml
index e045dd2..2410b6a 100644
--- a/packages/Keyguard/res/values/attrs.xml
+++ b/packages/Keyguard/res/values/attrs.xml
@@ -133,4 +133,8 @@
<attr name="digit" format="integer" />
<attr name="textView" format="reference" />
</declare-styleable>
+
+ <declare-styleable name="CarrierText">
+ <attr name="allCaps" format="boolean" />
+ </declare-styleable>
</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
index 88558cd..05f2962 100644
--- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java
+++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
@@ -17,6 +17,7 @@
package com.android.keyguard;
import android.content.Context;
+import android.content.res.TypedArray;
import android.text.method.SingleLineTransformationMethod;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -81,7 +82,14 @@
public CarrierText(Context context, AttributeSet attrs) {
super(context, attrs);
mLockPatternUtils = new LockPatternUtils(mContext);
- boolean useAllCaps = mContext.getResources().getBoolean(R.bool.kg_use_all_caps);
+ boolean useAllCaps;
+ TypedArray a = context.getTheme().obtainStyledAttributes(
+ attrs, R.styleable.CarrierText, 0, 0);
+ try {
+ useAllCaps = a.getBoolean(R.styleable.CarrierText_allCaps, false);
+ } finally {
+ a.recycle();
+ }
setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps));
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
index 2e4dbdf..ede23ef 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
@@ -27,11 +27,10 @@
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.MutableInt;
import android.view.View;
import android.widget.TextView;
-import libcore.util.MutableInt;
-
import java.lang.ref.WeakReference;
import com.android.internal.widget.LockPatternUtils;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 73c2840..ba67a82 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -215,8 +215,29 @@
mUserHasTrust.put(userId, enabled);
}
+ private boolean isTrustDisabled(int userId) {
+ final DevicePolicyManager dpm =
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ // TODO once UI is finalized
+ final boolean disabledByGlobalActions = false;
+ final boolean disabledBySettings = false;
+
+ // Don't allow trust agent if device is secured with a SIM PIN. This is here
+ // mainly because there's no other way to prompt the user to enter their SIM PIN
+ // once they get past the keyguard screen.
+ final boolean disabledBySimPin = isSimPinSecure();
+
+ final boolean disabledByDpm = (dpm.getKeyguardDisabledFeatures(null, userId)
+ & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+ return disabledByDpm || disabledByGlobalActions || disabledBySettings
+ || disabledBySimPin;
+ }
+ return false;
+ }
+
public boolean getUserHasTrust(int userId) {
- return mUserHasTrust.get(userId);
+ return !isTrustDisabled(userId) && mUserHasTrust.get(userId);
}
static class DisplayClientState {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e1c17cb..56f5a3a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -88,7 +88,7 @@
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
- <uses-permission android:name="android.permission.RENDER_STATS" />
+ <uses-permission android:name="android.permission.FRAME_STATS" />
<application android:label="@string/app_label">
<provider
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 88b01c7..809adcd 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -31,4 +31,14 @@
android:scaleType="center"
android:contentDescription="@string/accessibility_camera_button"
systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
+
+ <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="100dp"
+ android:layout_gravity="bottom|center_horizontal"
+ android:textStyle="italic"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 4442bca..ddc0dbf 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -22,26 +22,26 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.android.systemui.recents.views.TaskInfoView
- android:id="@+id/task_view_info_pane"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"
- android:background="#e6444444">
+ android:id="@+id/task_view_info_pane"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ android:background="@color/recents_task_bar_default_background_color">
<Button
- android:id="@+id/task_view_app_info_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="20dp"
- android:layout_marginEnd="20dp"
- android:layout_gravity="top|center_horizontal"
- android:text="@string/recents_app_info_button_label" />
+ android:id="@+id/task_view_app_info_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="20dp"
+ android:layout_marginEnd="20dp"
+ android:layout_gravity="top|center_horizontal"
+ android:text="@string/recents_app_info_button_label" />
</com.android.systemui.recents.views.TaskInfoView>
<com.android.systemui.recents.views.TaskBarView
android:id="@+id/task_view_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
- android:background="#e6444444">
+ android:background="@color/recents_task_bar_default_background_color">
<ImageView
android:id="@+id/application_icon"
android:layout_width="@dimen/recents_task_view_application_icon_size"
@@ -54,8 +54,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|left"
android:layout_marginStart="@dimen/recents_task_view_application_icon_size"
- android:layout_marginEnd="@dimen/recents_task_view_activity_icon_size"
- android:textSize="24sp"
+ android:layout_marginEnd="8dp"
+ android:textSize="22sp"
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
android:fontFamily="sans-serif-thin"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 69fbc1b..24ccb2b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -45,6 +45,15 @@
android:layout_marginTop="@dimen/status_bar_height"
android:visibility="gone" />
+ <com.android.keyguard.CarrierText
+ android:id="@+id/keyguard_carrier_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"
+ android:layout_marginLeft="8dp"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index 5d2f330..d81e525 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -19,34 +19,27 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:clickable="true"
+ android:background="@*android:drawable/notification_quantum_bg_dim"
>
- <com.android.systemui.statusbar.LatestItemView
- android:id="@+id/container"
+ <TextView
+ android:id="@+id/more_text"
android:layout_width="match_parent"
- android:layout_height="40dp"
- android:layout_marginTop="@dimen/notification_divider_height"
- android:focusable="true"
- android:clickable="true"
- android:background="@*android:drawable/notification_quantum_bg_dim"
- >
- <TextView
- android:id="@+id/more_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:gravity="center_horizontal"
- android:textColor="@color/keyguard_overflow_content_color"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- />
- <com.android.systemui.statusbar.NotificationOverflowIconsView
- android:id="@+id/overflow_icons_view"
- android:layout_gravity="end|center_vertical"
- android:gravity="end"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:layout_width="120dp"
- android:layout_height="wrap_content"
- />
- </com.android.systemui.statusbar.LatestItemView>
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="center_horizontal"
+ android:textColor="@color/keyguard_overflow_content_color"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+ <com.android.systemui.statusbar.NotificationOverflowIconsView
+ android:id="@+id/overflow_icons_view"
+ android:layout_gravity="end|center_vertical"
+ android:gravity="end"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ />
</com.android.systemui.statusbar.NotificationOverflowContainer>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index d61d8b9..41e7dac 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -2,17 +2,18 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:focusable="true"
+ android:clickable="true"
+ android:background="@*android:drawable/notification_quantum_bg"
>
- <View
- android:id="@+id/top_glow"
- android:alpha="0"
- android:visibility="invisible"
+ <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expanded"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expandedPublic"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_divider_height"
- android:layout_gravity="top|center_horizontal"
- android:background="@drawable/top_divider_glow"
- />
+ android:layout_height="wrap_content" />
<Button
android:id="@+id/veto"
@@ -25,35 +26,6 @@
android:paddingStart="8dp"
/>
- <com.android.systemui.statusbar.LatestItemView android:id="@+id/container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/notification_divider_height"
- android:layout_marginTop="@dimen/notification_divider_height"
- android:focusable="true"
- android:clickable="true"
- android:background="@*android:drawable/notification_quantum_bg"
- >
-
- <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expanded"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expandedPublic"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- </com.android.systemui.statusbar.LatestItemView>
-
- <View
- android:id="@+id/bottom_glow"
- android:alpha="0"
- android:visibility="invisible"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_divider_height"
- android:layout_gravity="bottom|center_horizontal"
- android:background="@drawable/bottom_divider_glow"
- />
-
<TextView
android:id="@+id/debug_info"
android:visibility="invisible"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 098ecdd..285978b 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Kleurregstellingmodus"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ONLANGS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk word\ndalk gemonitor"</string>
<string name="description_target_search" msgid="3091587249776033139">"Soek"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Gly op vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d kennisgewings versteek"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Raak om te wys"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Moenie steur nie"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d meer"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 75fbaf0..430c209 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"የቀለም እርማት ሁነታ"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"የቅርብ ጊዜዎች"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"አውታረ መረብ\nክትትል ሊደረግበት ይችላል"</string>
<string name="description_target_search" msgid="3091587249776033139">"ፍለጋ"</string>
<string name="description_direction_up" msgid="7169032478259485180">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ላይ አንሸራትት።"</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d ማሳወቂያዎች ተደብቀዋል"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ለማሳየት ነካ ያድርጉ"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ተጨማሪ"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index fd7f791..3186791 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"وضع تصحيح الألوان"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"الأخيرة"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string>
<string name="description_target_search" msgid="3091587249776033139">"بحث"</string>
<string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"تم إخفاء %d من الإشعارات"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"المس للعرض"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"الرجاء عدم الإزعاج"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d أخرى"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 426471c..b79429c 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим на коригиране на цветовете"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"СКОРОШНИ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежата може\nда се наблюдава"</string>
<string name="description_target_search" msgid="3091587249776033139">"Търсене"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Плъзнете нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d известия са скрити"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Докоснете за показване"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Още %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7365377..1841622 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correcció de color"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string>
<string name="description_target_search" msgid="3091587249776033139">"Cerca"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Fes lliscar el dit cap amunt per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notificacions ocultes"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca per mostrar-ho."</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"No molesteu"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d més"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 8455e43..1c2e122 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Režim korekce barev"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"POSLEDNÍ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Síť může být\nmonitorována"</string>
<string name="description_target_search" msgid="3091587249776033139">"Vyhledávání"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Přejeďte prstem nahoru: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"Skrytá oznámení: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Oznámení zobrazíte kliknutím"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Další: %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 56bf53b..62ab0c3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Farvekorrigeringstilstand"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"SENESTE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string>
<string name="description_target_search" msgid="3091587249776033139">"Søgning"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d underretninger er skjult"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryk for at vise"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Vil ikke forstyrres"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d mere"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 04b1767..a73e6d7 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -165,7 +165,7 @@
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Daten erneut 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>
- <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht"</string>
+ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht..."</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Standortanfragen aktiv"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string>
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Farbkorrekturmodus"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"Letzte"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string>
<string name="description_target_search" msgid="3091587249776033139">"Suche"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d Benachrichtigungen ausgeblendet"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Zum Ansehen tippen"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Nicht stören"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d mehr"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index b3404be..caf64f5 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Λειτουργία διόρθωσης χρώματος"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ΠΡΟΣΦΑΤΑ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string>
<string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"Έγινε απόκρυψη %d ειδοποιήσεων"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Αγγίξτε για εμφάνιση"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Μην ενοχλείτε"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ακόμη"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index ff2e525..7eff6ee 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
<string name="description_target_search" msgid="3091587249776033139">"Search"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d more"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index ff2e525..7eff6ee 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
<string name="description_target_search" msgid="3091587249776033139">"Search"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d more"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index bdd5885..d2a1125 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de corrección de color"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Es posible que la red\nesté supervisada."</string>
<string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notificaciones ocultas"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca para mostrar"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"No molestar"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d más"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c8e26d2..822db03 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de corrección de color"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string>
<string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notificaciones ocultas"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca para mostrar"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"No molestar"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d más"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 2a8314d..027de0c 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -205,7 +205,8 @@
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Täiustatud kontrasti režiim"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Värviparandusrežiim"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"HILJUTISED"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduse teave"</string>
+ <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Võrku võidakse\njälgida"</string>
<string name="description_target_search" msgid="3091587249776033139">"Otsing"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -213,6 +214,8 @@
<!-- String.format failed for translation -->
<!-- no translation found for zen_mode_notification_title:other (7388721375827338153) -->
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Puudutage kuvamiseks"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Veel %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 9461948..53353ae 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"حالت تصحیح رنگ"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"موارد اخیر"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ممکن است شبکه\nتحت نظارت باشد"</string>
<string name="description_target_search" msgid="3091587249776033139">"جستجو"</string>
<string name="description_direction_up" msgid="7169032478259485180">"لغزاندن به بالا برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d اعلان پنهان شده"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"برای نمایش لمس کنید"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d بیشتر"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index bb81ffa..dad857c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -206,6 +206,8 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Värinkorjaustila"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"VIIMEISIMMÄT"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
+ <skip />
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string>
<string name="description_target_search" msgid="3091587249776033139">"Haku"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Liu\'uta ylös ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +217,8 @@
<item quantity="other" msgid="7388721375827338153">"%d ilmoitusta piilotettu"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Näytä koskettamalla"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d muuta"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 5232d22..f0eb784 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correction des couleurs"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RÉCENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
<string name="description_target_search" msgid="3091587249776033139">"Recherche"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Faire glisser le doigt vers le haut : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notifications masquées"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touchez pour afficher la notification"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Ne pas déranger"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d autres"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1cc8072..84dae3f 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correction des couleurs"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RÉCENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informations sur l\'application"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
<string name="description_target_search" msgid="3091587249776033139">"Rechercher"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Faites glisser vers le haut pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"%d notifications masquées"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Appuyer pour afficher"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"+ %d autres"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index fd7783d..2cdff20 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"रंग सुधार मोड"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"हाल ही का"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्लिकेशन जानकारी"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string>
<string name="description_target_search" msgid="3091587249776033139">"खोजें"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्लाइड करें."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d सूचनाएं छिपी हुई हैं"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"दिखाने के लिए स्पर्श करें"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"परेशान न करें"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d और"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b7c69d5..8b69a4d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Način korekcije boje"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNO"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"Broj skrivenih obavijesti: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dodirnite za prikaz"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Još %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index f374743..e9c7c7b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Színjavítás mód"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"LEGUTÓBBIAK"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string>
<string name="description_target_search" msgid="3091587249776033139">"Keresés"</string>
<string name="description_direction_up" msgid="7169032478259485180">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa felfelé."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d értesítés elrejtve"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"A megtekintéshez érintse meg"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Ne zavarjanak"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d további"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f2bbb7c..e2d69a0 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -206,6 +206,8 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Գույների կարգավորման ռեժիմ"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ՎԵՐՋԻՆՆԵՐԸ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
+ <skip />
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string>
<string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
@@ -215,6 +217,8 @@
<item quantity="other" msgid="7388721375827338153">"%d ծանուցում թաքցված է"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Հպեք՝ ցուցադրելու համար"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Եվս %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index ccd6c68..c3ec03b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode koreksi warna"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"TERBARU"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string>
<string name="description_target_search" msgid="3091587249776033139">"Telusuri"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d pemberitahuan disembunyikan"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menampilkan"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Jangan ganggu"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d lainnya"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 1c0f712..60f9fc8 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modalità di correzione del colore"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"MESSAGGI RECENTI"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string>
<string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notifiche nascoste"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tocca per visualizzare"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Non disturbare"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Altre %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 67ed8c5..f9dc2e7 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"מצב תיקון צבע"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"אחרונים"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ייתכן שהרשת\nמנוטרת"</string>
<string name="description_target_search" msgid="3091587249776033139">"חיפוש"</string>
<string name="description_direction_up" msgid="7169032478259485180">"הסט למעלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d הודעות הוסתרו"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"גע כדי להציג"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"נא לא להפריע"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"עוד %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 14309ab..73fb622 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"色補正モード"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"最近"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ネットワークが監視される\n場合があります"</string>
<string name="description_target_search" msgid="3091587249776033139">"検索します"</string>
<string name="description_direction_up" msgid="7169032478259485180">"上にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"%d件の通知が非表示"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"表示するにはタップします"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"他%d件"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 904ae01..0cd7812 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -205,7 +205,8 @@
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"გაუმჯობესებული კონტრასტის რეჟიმი"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"ფერთა კორექციის რეჟიმი"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ბოლო დროის"</string>
- <!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
+ <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
<skip />
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string>
<string name="description_target_search" msgid="3091587249776033139">"ძიება"</string>
@@ -216,6 +217,8 @@
<item quantity="other" msgid="7388721375827338153">"%d შეტყობინება დამალულია"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"შეეხეთ საჩვენებლად"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d სხვა"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 5ce1be3..30eae2e 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"របៀបកែពណ៌"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ថ្មីៗ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មានកម្មវិធី"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string>
<string name="description_direction_up" msgid="7169032478259485180">"រុញឡើងលើដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"បានលាក់ការជូនដំណឹង %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ប៉ះដើម្បីបង្ហាញ"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"កុំរំខាន"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ទៀត"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 99e1ac0..e1ab831 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"색상 보정 모드"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"최근"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"네트워크가\n모니터링될 수 있음"</string>
<string name="description_target_search" msgid="3091587249776033139">"검색"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 위로 슬라이드"</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"알림 %d개 숨김"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"표시하려면 터치"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d개 더보기"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index a09a310..3ade551 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"ໂໝດການແກ້ໄຂສີ"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ບໍ່ດົນມານີ້"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ຂໍ້ມູນແອັບພລິເຄຊັນ"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string>
<string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"ເຊື່ອງ %d ການແຈ້ງເຕືອນແລ້ວ"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ແຕະເພື່ອສະແດງ"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ເພີ່ມເຕີມ"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 6fa96aa..3dc6a7a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Spalvų taisymo režimas"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"PASTARIEJI"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string>
<string name="description_target_search" msgid="3091587249776033139">"Paieška"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"Paslėpta pranešimų: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Palieskite, kad būtų rodoma"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Netrukdyti"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Dar %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 19602a6..9405545 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Krāsu korekcijas režīms"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"JAUNĀKIE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string>
<string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d paziņojumi paslēpti"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Pieskarieties, lai rādītu"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Netraucēt"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"vēl %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 1ff647f..99ecacf 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Өнгө залруулах горим"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"СҮҮЛИЙН"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Сүлжээ хянагдаж\nбайж болзошгүй"</string>
<string name="description_target_search" msgid="3091587249776033139">"Хайх"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-г гулсуулах."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d мэдэгдлийг нуусан"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Харуулах бол хүрнэ үү"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Бүү саад бол"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"өөр %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 77c1c9d..886d644 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -205,8 +205,8 @@
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mod kontras dipertingkat"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mod pembetulan warna"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"TERBAHARU"</string>
- <!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
- <skip />
+ <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string>
<string name="description_target_search" msgid="3091587249776033139">"Carian"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -216,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d pemberitahuan disembunyikan"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menunjukkan"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d lagi"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index dd8c531..1892632 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus for fargekorrigering"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NYLIGE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string>
<string name="description_target_search" msgid="3091587249776033139">"Søk"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d varsler er skjult"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Trykk for å vise"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d til"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a4d8d22..bf4d765 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus voor kleurcorrectie"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string>
<string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d meldingen verborgen"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Raak aan om weer te geven"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Niet storen"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Nog %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 2a5b0f8..57605b2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Tryb korekcji kolorów"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"OSTATNIE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieć może być\nmonitorowana"</string>
<string name="description_target_search" msgid="3091587249776033139">"Szukaj"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Przesuń w górę: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"Ukryte powiadomienia: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dotknij, by zobaczyć"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Nie przeszkadzać"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d więcej"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 39cfe4d..fc71887 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Deslize para cima para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notificações ocultas"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Não incomodar"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 6d712c3..d1ed7ac 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do aplicativo"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode estar\nsob monitoração"</string>
<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>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"%d notificações ocultas"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 4ab5e75..4e0f0f6 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -382,6 +382,8 @@
<skip />
<!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
<skip />
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
+ <skip />
<!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
<skip />
<!-- no translation found for description_target_search (3091587249776033139) -->
@@ -394,5 +396,7 @@
<!-- no translation found for zen_mode_notification_title:other (7388721375827338153) -->
<!-- no translation found for zen_mode_notification_text (8336623711388065713) -->
<skip />
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<!-- no translation found for keyguard_more_overflow_text:other (9180696159506883684) -->
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2e8c7a6..cef305c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -206,6 +206,8 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mod de corectare a culorilor"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
+ <skip />
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
<string name="description_target_search" msgid="3091587249776033139">"Căutaţi"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +217,8 @@
<item quantity="other" msgid="7388721375827338153">"%d de notificări ascunse"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Atingeți pentru a afișa"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Încă %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 643759f..ef4b6ee 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -178,9 +178,7 @@
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим полета"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <!-- String.format failed for translation -->
- <!-- no translation found for quick_settings_battery_charged_label (8865413079414246081) -->
- <skip />
+ <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"100%%"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth выкл."</string>
@@ -210,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Коррекция цвета"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"НЕДАВНИЕ СООБЩЕНИЯ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Действия в сети\nмогут отслеживаться"</string>
<string name="description_target_search" msgid="3091587249776033139">"Поиск"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Проведите вверх, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -219,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"Скрыто оповещений: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Нажмите, чтобы открыть"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Ещё %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 3daf9f9..11e8b26 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Režim korekcie farieb"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NEDÁVNE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieť môže byť\nmonitorovaná"</string>
<string name="description_target_search" msgid="3091587249776033139">"Vyhľadávanie"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Prejdite prstom nahor: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"Skryté upozornenia: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Upozornenie zobrazíte dotykom"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ďalších"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index acda247..00d0086 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Način popravljanja barv"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNI"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string>
<string name="description_target_search" msgid="3091587249776033139">"Iskanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Povlecite navzgor za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"Skritih je toliko obvestil: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dotaknite se za prikaz"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Ne moti"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"še %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 4331c7f..0f8686c 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим корекције боје"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"НАЈНОВИЈЕ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
<string name="description_target_search" msgid="3091587249776033139">"Претрага"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"Сакривена обавештења: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Додирните за приказ"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Још %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index cb591c12..a0e1468 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Färgkorrigeringsläge"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NYA"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string>
<string name="description_target_search" msgid="3091587249776033139">"Sök"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d aviseringar har dolts"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryck här om du vill visa aviseringar"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Stör ej"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d till"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 11e2435..2c84b19 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -204,6 +204,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Hali ya kusahihisha rangi"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"YA HIVI KARIBUNI"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string>
<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>
@@ -213,6 +214,8 @@
<item quantity="other" msgid="7388721375827338153">"Arifa %d zimefichwa"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Gusa ili zionekane"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d zaidi"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 33fded2..1ebe21c 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"โหมดการแก้ไขสี"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ล่าสุด"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"เครือข่ายอาจ\nถูกตรวจสอบ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ค้นหา"</string>
<string name="description_direction_up" msgid="7169032478259485180">"เลื่อนขึ้นเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"ซ่อน %d การแจ้งเตือนแล้ว"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"แตะเพื่อแสดง"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"ห้ามรบกวน"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"อีก %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 57b882c..eb8f236 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode ng pagtatama ng kulay"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"MGA KAMAKAILAN"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Maaaring\nsinusubaybayan ang network"</string>
<string name="description_target_search" msgid="3091587249776033139">"Maghanap"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Mag-slide pataas para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"Nakatago ang %d (na) notification"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Pindutin upang ipakita"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d pa"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 43e199e..1b57a94 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Renk düzeltme modu"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"SON İLETİLER"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ağ izleniyor\nolabilir"</string>
<string name="description_target_search" msgid="3091587249776033139">"Ara"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için yukarı kaydırın."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d bildirim gizli"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Görüntülemek için dokunun"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d adet daha"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index cab6b65..60192d7 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим коригування кольору"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ОСТАННІ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string>
<string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"Сховано сповіщень: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Торкніться, щоб показати"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Не турбувати"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Ще %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index bfbbf01..8770854 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Chế độ hiệu chỉnh màu sắc"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"GẦN ĐÂY"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mạng có thể\nđược giám sát"</string>
<string name="description_target_search" msgid="3091587249776033139">"Tìm kiếm"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Trượt lên để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d thông báo ẩn"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Chạm để hiển thị"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d thông báo khác"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ede3b61..89250a5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"颜色校正模式"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"最近"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"网络可能会\n受到监控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜索"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"隐藏了%d条通知"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"触摸即可显示"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"还有%d条"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 006ce3e..6fb723e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"色彩校準模式"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"近期"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"已隱藏 %d 則通知"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"請勿騷擾"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"還有 %d 個"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2a56c3f..9ceb4e9 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"色彩校正模式"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"近期"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網路可能\n受到監控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"已隱藏 %d 則通知"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"還有 %d 則"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a2defee..81a08d9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Imodi yokulungisa umbala"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"OKWAKAMUVA"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string>
<string name="description_target_search" msgid="3091587249776033139">"Sesha"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Shelelisela ngenhla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d izaziso zifihliwe"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Thinta ukuze ubonise"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Ungaphazamisi"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d okuningi"</item>
</plurals>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 59e8360..9281265 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -49,4 +49,14 @@
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff666666</color>
+
+ <!-- The default recents task bar background color. -->
+ <color name="recents_task_bar_default_background_color">#e6444444</color>
+ <!-- The default recents task bar text color. -->
+ <color name="recents_task_bar_default_text_color">#ffffffff</color>
+ <!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
+ <color name="recents_task_bar_light_text_color">#ffffffff</color>
+ <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
+ <color name="recents_task_bar_dark_text_color">#ff222222</color>
+
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0604817..176879e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -82,12 +82,6 @@
<!-- Height of a medium notification in the status bar -->
<dimen name="notification_mid_height">128dp</dimen>
- <!-- Height of a small notification in the status bar plus glow, padding, etc -->
- <dimen name="notification_row_min_height">68dp</dimen>
-
- <!-- Height of a large notification in the status bar plus glow, padding, etc -->
- <dimen name="notification_row_max_height">260dp</dimen>
-
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">18dip</dimen>
@@ -261,6 +255,9 @@
<!-- Z distance between notifications if they are in the stack -->
<dimen name="z_distance_between_notifications">2dp</dimen>
+ <!-- The padding between the individual notification cards. -->
+ <dimen name="notification_padding">3dp</dimen>
+
<!-- Width of the zen mode interstitial dialog. -->
<dimen name="zen_mode_dialog_width">320dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f3c956c..b4a13d4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -546,4 +546,10 @@
<plurals name="keyguard_more_overflow_text">
<item quantity="other">%d more</item>
</plurals>
+
+ <!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
+ <string name="notification_tap_again">Tap again to open</string>
+
+ <!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] -->
+ <string name="keyguard_unlock">Swipe up to unlock</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 8dd3f8d..c585a5b 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -19,7 +19,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.media.AudioManager;
@@ -81,8 +80,6 @@
private boolean mHasPopped;
private View mEventSource;
private View mCurrView;
- private View mCurrViewTopGlow;
- private View mCurrViewBottomGlow;
private float mOldHeight;
private float mNaturalHeight;
private float mInitialTouchFocusY;
@@ -99,9 +96,6 @@
private ScaleGestureDetector mSGD;
private ViewScaler mScaler;
private ObjectAnimator mScaleAnimation;
- private AnimatorSet mGlowAnimationSet;
- private ObjectAnimator mGlowTopAnimation;
- private ObjectAnimator mGlowBottomAnimation;
private Vibrator mVibrator;
private int mSmallSize;
@@ -223,14 +217,6 @@
}
};
- mGlowTopAnimation = ObjectAnimator.ofFloat(null, "alpha", 0f);
- mGlowTopAnimation.addListener(glowVisibilityController);
- mGlowBottomAnimation = ObjectAnimator.ofFloat(null, "alpha", 0f);
- mGlowBottomAnimation.addListener(glowVisibilityController);
- mGlowAnimationSet = new AnimatorSet();
- mGlowAnimationSet.play(mGlowTopAnimation).with(mGlowBottomAnimation);
- mGlowAnimationSet.setDuration(GLOW_DURATION);
-
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
mTouchSlop = configuration.getScaledTouchSlop();
@@ -251,7 +237,6 @@
float newHeight = clamp(target);
mScaler.setHeight(newHeight);
- setGlow(calculateGlow(target, newHeight));
mLastFocusY = mSGD.getFocusY();
mLastSpanY = mSGD.getCurrentSpan();
}
@@ -322,37 +307,6 @@
return (GLOW_BASE + strength * (1f - GLOW_BASE));
}
- public void setGlow(float glow) {
- if (!mGlowAnimationSet.isRunning() || glow == 0f) {
- if (mGlowAnimationSet.isRunning()) {
- mGlowAnimationSet.end();
- }
- if (mCurrViewTopGlow != null && mCurrViewBottomGlow != null) {
- if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) {
- // animate glow in and out
- mGlowTopAnimation.setTarget(mCurrViewTopGlow);
- mGlowBottomAnimation.setTarget(mCurrViewBottomGlow);
- mGlowTopAnimation.setFloatValues(glow);
- mGlowBottomAnimation.setFloatValues(glow);
- mGlowAnimationSet.setupStartValues();
- mGlowAnimationSet.start();
- } else {
- // set it explicitly in reponse to touches.
- mCurrViewTopGlow.setAlpha(glow);
- mCurrViewBottomGlow.setAlpha(glow);
- handleGlowVisibility();
- }
- }
- }
- }
-
- private void handleGlowVisibility() {
- mCurrViewTopGlow.setVisibility(mCurrViewTopGlow.getAlpha() <= 0.0f ?
- View.INVISIBLE : View.VISIBLE);
- mCurrViewBottomGlow.setVisibility(mCurrViewBottomGlow.getAlpha() <= 0.0f ?
- View.INVISIBLE : View.VISIBLE);
- }
-
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
@@ -466,9 +420,6 @@
if (mHasPopped) {
mScaler.setHeight(newHeight);
- setGlow(GLOW_BASE);
- } else {
- setGlow(calculateGlow(4f * pull, 0f));
}
final int x = (int) mSGD.getFocusX();
@@ -517,7 +468,6 @@
if (DEBUG) Log.d(TAG, "scale type " + expandType + " beginning on view: " + v);
mCallback.setUserLockedChild(v, true);
setView(v);
- setGlow(GLOW_BASE);
mScaler.setView(v);
mOldHeight = mScaler.getHeight();
if (mCallback.canChildBeExpanded(v)) {
@@ -549,7 +499,6 @@
if (mScaleAnimation.isRunning()) {
mScaleAnimation.cancel();
}
- setGlow(0f);
mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight);
if (targetHeight != currentHeight) {
mScaleAnimation.setFloatValues(targetHeight);
@@ -571,23 +520,11 @@
private void clearView() {
mCurrView = null;
- mCurrViewTopGlow = null;
- mCurrViewBottomGlow = null;
+
}
private void setView(View v) {
mCurrView = v;
- if (v instanceof ViewGroup) {
- ViewGroup g = (ViewGroup) v;
- mCurrViewTopGlow = g.findViewById(R.id.top_glow);
- mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow);
- if (DEBUG) {
- String debugLog = "Looking for glows: " +
- (mCurrViewTopGlow != null ? "found top " : "didn't find top") +
- (mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom");
- Log.v(TAG, debugLog);
- }
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index 21c2926..ae18aa8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -50,7 +50,8 @@
@Override
public void start() {
- mUseAlternateRecents = SystemProperties.getBoolean("persist.recents.use_alternate", false);
+ Configuration config = mContext.getResources().getConfiguration();
+ mUseAlternateRecents = (config.smallestScreenWidthDp < 600);
if (mUseAlternateRecents) {
if (mAlternateRecents == null) {
mAlternateRecents = new AlternateRecentsComponent(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index da265e1..52bba4a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -413,6 +413,8 @@
for (int i = 0; i < taskCount; i++) {
ActivityManager.RecentTaskInfo t = tasks.get(i);
ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
+ if (info == null) continue;
+
String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
t.activityLabel.toString());
BitmapDrawable activityIcon = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 5e90084..d647dfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 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.
@@ -11,7 +11,7 @@
* 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.
+ * limitations under the License
*/
package com.android.systemui.statusbar;
@@ -21,12 +21,15 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import com.android.internal.R;
-public class LatestItemView extends FrameLayout {
+/**
+ * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
+ * to implement dimming/activating on Keyguard for the double-tap gesture
+ */
+public class ActivatableNotificationView extends FrameLayout {
private static final long DOUBLETAP_TIMEOUT_MS = 1000;
@@ -48,11 +51,12 @@
private OnActivatedListener mOnActivatedListener;
- public LatestItemView(Context context, AttributeSet attrs) {
+ public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
+
private final Runnable mTapTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -66,20 +70,6 @@
}
@Override
- public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
- if (super.onRequestSendAccessibilityEvent(child, event)) {
- // Add a record for the entire layout since its content is somehow small.
- // The event comes from a leaf view that is interacted with.
- AccessibilityEvent record = AccessibilityEvent.obtain();
- onInitializeAccessibilityEvent(record);
- dispatchPopulateAccessibilityEvent(record);
- event.appendRecord(record);
- return true;
- }
- return false;
- }
-
- @Override
public boolean onTouchEvent(MotionEvent event) {
if (mLocked) {
return handleTouchEventLocked(event);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2ea5add..3e21640 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -83,7 +83,7 @@
import java.util.Locale;
public abstract class BaseStatusBar extends SystemUI implements
- CommandQueue.Callbacks, LatestItemView.OnActivatedListener {
+ CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener {
public static final String TAG = "StatusBar";
public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
@@ -737,8 +737,9 @@
return false;
}
- Log.v(TAG, "publicNotification: "
- + sbn.getNotification().publicVersion);
+ if (DEBUG) {
+ Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion);
+ }
Notification publicNotification = sbn.getNotification().publicVersion;
@@ -759,20 +760,19 @@
// NB: the large icon is now handled entirely by the template
// bind the click event to the content area
- ViewGroup content = (ViewGroup)row.findViewById(R.id.container);
SizeAdaptiveLayout expanded = (SizeAdaptiveLayout)row.findViewById(R.id.expanded);
SizeAdaptiveLayout expandedPublic
= (SizeAdaptiveLayout)row.findViewById(R.id.expandedPublic);
- content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
PendingIntent contentIntent = sbn.getNotification().contentIntent;
if (contentIntent != null) {
final View.OnClickListener listener = makeClicker(contentIntent,
sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp, sbn.getUserId());
- content.setOnClickListener(listener);
+ row.setOnClickListener(listener);
} else {
- content.setOnClickListener(null);
+ row.setOnClickListener(null);
}
// set up the adaptive layout
@@ -882,7 +882,6 @@
entry.row = row;
entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
entry.row.setOnActivatedListener(this);
- entry.content = content;
entry.expanded = contentViewLocal;
entry.expandedPublic = publicViewLocal;
entry.setBigContentView(bigContentViewLocal);
@@ -1349,9 +1348,9 @@
final View.OnClickListener listener = makeClicker(contentIntent,
notification.getPackageName(), notification.getTag(), notification.getId(),
isHeadsUp, notification.getUserId());
- entry.content.setOnClickListener(listener);
+ entry.row.setOnClickListener(listener);
} else {
- entry.content.setOnClickListener(null);
+ entry.row.setOnClickListener(null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index bb481ec..35c02eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -20,13 +20,12 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.FrameLayout;
+import android.view.accessibility.AccessibilityEvent;
import com.android.internal.widget.SizeAdaptiveLayout;
import com.android.systemui.R;
-public class ExpandableNotificationRow extends FrameLayout
- implements LatestItemView.OnActivatedListener {
+public class ExpandableNotificationRow extends ActivatableNotificationView {
private int mRowMinHeight;
private int mRowMaxHeight;
@@ -41,8 +40,6 @@
/** Are we showing the "public" version */
private boolean mShowingPublic;
- private LatestItemView mLatestItemView;
-
/**
* Is this notification expanded by the system. The expansion state can be overridden by the
* user expansion.
@@ -53,7 +50,6 @@
private int mMaxExpandHeight;
private boolean mMaxHeightNeedsUpdate;
private NotificationActivator mActivator;
- private LatestItemView.OnActivatedListener mOnActivatedListener;
private boolean mSelfInitiatedLayout;
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
@@ -65,10 +61,22 @@
super.onFinishInflate();
mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic);
mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded);
- mLatestItemView = (LatestItemView) findViewById(R.id.container);
mActivator = new NotificationActivator(this);
- mLatestItemView.setOnActivatedListener(this);
+ }
+
+ @Override
+ public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ if (super.onRequestSendAccessibilityEvent(child, event)) {
+ // Add a record for the entire layout since its content is somehow small.
+ // The event comes from a leaf view that is interacted with.
+ AccessibilityEvent record = AccessibilityEvent.obtain();
+ onInitializeAccessibilityEvent(record);
+ dispatchPopulateAccessibilityEvent(record);
+ event.appendRecord(record);
+ return true;
+ }
+ return false;
}
public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
@@ -220,7 +228,7 @@
* Sets the notification as dimmed, meaning that it will appear in a more gray variant.
*/
public void setDimmed(boolean dimmed) {
- mLatestItemView.setDimmed(dimmed);
+ super.setDimmed(dimmed);
mActivator.setDimmed(dimmed);
}
@@ -232,46 +240,10 @@
return mMaxExpandHeight;
}
- /**
- * Sets the notification as locked. In the locked state, the first tap will produce a quantum
- * ripple to make the notification brighter and only the second tap will cause a click.
- */
- public void setLocked(boolean locked) {
- mLatestItemView.setLocked(locked);
- }
-
- public void setOnActivatedListener(LatestItemView.OnActivatedListener listener) {
- mOnActivatedListener = listener;
- }
-
public NotificationActivator getActivator() {
return mActivator;
}
- @Override
- public void onActivated(View view) {
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onActivated(this);
- }
- }
-
- @Override
- public void onReset(View view) {
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onReset(this);
- }
- }
-
- /**
- * Sets the resource id for the background of this notification.
- *
- * @param bgResId The background resource to use in normal state.
- * @param dimmedBgResId The background resource to use in dimmed state.
- */
- public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
- mLatestItemView.setBackgroundResourceIds(bgResId, dimmedBgResId);
- }
-
/**
* @return the potential height this view could expand in addition.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index d563968..6401695 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -107,7 +107,7 @@
mBar.updateNotification(mSynKey, sbn);
}
final NotificationData.Entry entry = mBar.mNotificationData.findByKey(mSynKey);
- entry.content.setOnClickListener(mSynClickListener);
+ entry.row.setOnClickListener(mSynClickListener);
}
private final View.OnClickListener mSynClickListener = new View.OnClickListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index b9a59dd..6b6f55a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -33,7 +33,6 @@
public StatusBarNotification notification;
public StatusBarIconView icon;
public ExpandableNotificationRow row; // the outer expanded view
- public View content; // takes the click events and sends the PendingIntent
public View expanded; // the inflated RemoteViews
public View expandedPublic; // for insecure lockscreens
public ImageView largeIcon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index be58dad..af91314 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -18,8 +18,6 @@
import android.content.Context;
import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.systemui.R;
@@ -27,65 +25,30 @@
/**
* Container view for overflowing notification icons on Keyguard.
*/
-public class NotificationOverflowContainer extends FrameLayout
- implements LatestItemView.OnActivatedListener {
+public class NotificationOverflowContainer extends ActivatableNotificationView {
private NotificationOverflowIconsView mIconsView;
- private LatestItemView.OnActivatedListener mOnActivatedListener;
private NotificationActivator mActivator;
- public NotificationOverflowContainer(Context context) {
- super(context);
- }
-
public NotificationOverflowContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
- public NotificationOverflowContainer(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public NotificationOverflowContainer(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
- LatestItemView latestItemView = (LatestItemView) findViewById(R.id.container);
mActivator = new NotificationActivator(this);
mActivator.setDimmed(true);
- latestItemView.setOnActivatedListener(this);
- latestItemView.setLocked(true);
+ setLocked(true);
}
public NotificationOverflowIconsView getIconsView() {
return mIconsView;
}
- public void setOnActivatedListener(LatestItemView.OnActivatedListener onActivatedListener) {
- mOnActivatedListener = onActivatedListener;
- }
-
- @Override
- public void onActivated(View view) {
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onActivated(this);
- }
- }
-
- @Override
- public void onReset(View view) {
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onReset(this);
- }
- }
-
public NotificationActivator getActivator() {
return mActivator;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
new file mode 100644
index 0000000..769b1b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -0,0 +1,62 @@
+/*
+ * 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.util.AttributeSet;
+import android.widget.TextView;
+
+/**
+ * A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open").
+ */
+public class KeyguardIndicationTextView extends TextView {
+
+ public KeyguardIndicationTextView(Context context) {
+ super(context);
+ }
+
+ public KeyguardIndicationTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public KeyguardIndicationTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public KeyguardIndicationTextView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ /**
+ * Changes the text with an animation and makes sure a single indication is shown long enough.
+ *
+ * @param text The text to show.
+ */
+ public void switchIndication(CharSequence text) {
+
+ // TODO: Animation, make sure that we will show one indication long enough.
+ setText(text);
+ }
+
+ /**
+ * See {@link #switchIndication}.
+ */
+ public void switchIndication(int textResId) {
+ switchIndication(getResources().getText(textResId));
+ }
+}
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 7f1ddaf..545352c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -232,6 +232,10 @@
View mNotificationPanelHeader;
View mKeyguardStatusView;
View mKeyguardBottomArea;
+ KeyguardIndicationTextView mKeyguardIndicationTextView;
+
+ // TODO: Fetch phrase from search/hotword provider.
+ String mKeyguardHotwordPhrase = "";
int mKeyguardMaxNotificationCount;
View mDateTimeView;
View mClearButton;
@@ -243,6 +247,7 @@
private int mCarrierLabelHeight;
private TextView mEmergencyCallLabel;
private int mNotificationHeaderHeight;
+ private View mKeyguardCarrierLabel;
private boolean mShowCarrierInPanel = false;
@@ -371,6 +376,7 @@
private InterceptedNotifications mIntercepted;
private VelocityTracker mSettingsTracker;
private float mSettingsDownY;
+ private boolean mSettingsStarted;
private boolean mSettingsCancelled;
private boolean mSettingsClosing;
private int mNotificationPadding;
@@ -611,6 +617,7 @@
(NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
mKeyguardIconOverflowContainer.setOnActivatedListener(this);
+ mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text);
mStackScroller.addView(mKeyguardIconOverflowContainer);
mExpandedContents = mStackScroller;
@@ -618,7 +625,8 @@
mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
mKeyguardBottomArea = mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
-
+ mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
+ R.id.keyguard_indication_text);
mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
mClearButton.setOnClickListener(mClearButtonListener);
mClearButton.setAlpha(0f);
@@ -761,16 +769,16 @@
if (mSettingsTracker != null) {
mSettingsTracker.addMovement(event);
}
-
+ final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mSettingsTracker = VelocityTracker.obtain();
mSettingsDownY = event.getY();
mSettingsCancelled = false;
+ mSettingsStarted = false;
mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE;
- mFlipSettingsView.setVisibility(View.VISIBLE);
- mStackScroller.setVisibility(View.VISIBLE);
- positionSettings(0);
- if (!mSettingsClosing) {
+ if (mSettingsClosing) {
+ mStackScroller.setVisibility(View.VISIBLE);
+ } else {
mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight());
}
dispatchSettingsEvent(event);
@@ -779,8 +787,7 @@
final float dy = event.getY() - mSettingsDownY;
final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper;
final boolean inButton = flipper.inHolderBounds(event);
- final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
+ final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
if (!qsTap && !inButton) {
mSettingsTracker.computeCurrentVelocity(1000);
final float vy = mSettingsTracker.getYVelocity();
@@ -796,10 +803,9 @@
dispatchSettingsEvent(event);
} else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) {
final float dy = event.getY() - mSettingsDownY;
- positionSettings(dy);
if (mSettingsClosing) {
- final boolean qsTap =
- Math.abs(dy) < ViewConfiguration.get(mContext).getScaledTouchSlop();
+ positionSettings(dy);
+ final boolean qsTap = Math.abs(dy) < slop;
if (!mSettingsCancelled && !qsTap) {
MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
@@ -807,6 +813,14 @@
mSettingsCancelled = true;
}
} else {
+ if (!mSettingsStarted && dy > slop) {
+ mSettingsStarted = true;
+ mFlipSettingsView.setVisibility(View.VISIBLE);
+ mStackScroller.setVisibility(View.VISIBLE);
+ }
+ if (mSettingsStarted) {
+ positionSettings(dy);
+ }
dispatchSettingsEvent(event);
}
}
@@ -1332,7 +1346,8 @@
!(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
&& mStackScroller.getHeight() < (mNotificationPanel.getHeight()
- mCarrierLabelHeight - mNotificationHeaderHeight)
- && mStackScroller.getVisibility() == View.VISIBLE;
+ && mStackScroller.getVisibility() == View.VISIBLE
+ && !mOnKeyguard;
if (force || mCarrierLabelVisible != makeVisible) {
mCarrierLabelVisible = makeVisible;
@@ -1610,9 +1625,9 @@
return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0;
}
- void makeExpandedVisible() {
+ void makeExpandedVisible(boolean force) {
if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
- if (mExpandedVisible || !panelsEnabled()) {
+ if (!force && (mExpandedVisible || !panelsEnabled())) {
return;
}
@@ -2703,8 +2718,8 @@
}
mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
- mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_row_min_height);
- mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_row_max_height);
+ mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
+ mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count);
@@ -2942,6 +2957,9 @@
}
mKeyguardStatusView.setVisibility(View.VISIBLE);
mKeyguardBottomArea.setVisibility(View.VISIBLE);
+ mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ mKeyguardCarrierLabel.setVisibility(View.VISIBLE);
mNotificationPanelHeader.setVisibility(View.GONE);
mKeyguardFlipper.setVisibility(View.VISIBLE);
@@ -2949,6 +2967,8 @@
} else {
mKeyguardStatusView.setVisibility(View.GONE);
mKeyguardBottomArea.setVisibility(View.GONE);
+ mKeyguardIndicationTextView.setVisibility(View.GONE);
+ mKeyguardCarrierLabel.setVisibility(View.GONE);
mNotificationPanelHeader.setVisibility(View.VISIBLE);
mKeyguardFlipper.setVisibility(View.GONE);
@@ -2959,6 +2979,7 @@
updateRowStates();
checkBarModes();
updateNotificationIcons();
+ updateCarrierLabelVisibility(false);
}
public void userActivity() {
@@ -2987,14 +3008,23 @@
}
private void instantExpandNotificationsPanel() {
+
+ // Make our window larger and the panel visible.
+ makeExpandedVisible(true);
+ mNotificationPanel.setVisibility(View.VISIBLE);
+
+ // Wait for window manager to pickup the change, so we know the maximum height of the panel
+ // then.
mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- mNotificationPanel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- mNotificationPanel.setExpandedFraction(1);
- }
- });
+ @Override
+ public void onGlobalLayout() {
+ if (mStatusBarWindow.getHeight() != getStatusBarHeight()) {
+ mNotificationPanel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ mNotificationPanel.setExpandedFraction(1);
+ }
+ }
+ });
}
private void instantCollapseNotificationPanel() {
@@ -3004,10 +3034,29 @@
@Override
public void onActivated(View view) {
userActivity();
+ mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
super.onActivated(view);
}
@Override
+ public void onReset(View view) {
+ super.onReset(view);
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ }
+
+ public void onTrackingStarted() {
+ if (mOnKeyguard) {
+ mKeyguardIndicationTextView.switchIndication(R.string.keyguard_unlock);
+ }
+ }
+
+ public void onTrackingStopped() {
+ if (mOnKeyguard) {
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ }
+ }
+
+ @Override
protected int getMaxKeyguardNotifications() {
return mKeyguardMaxNotificationCount;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 8957a77..194774d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -168,6 +168,9 @@
if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
mSimState = IccCardConstants.State.ABSENT;
}
+ else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
+ mSimState = IccCardConstants.State.CARD_IO_ERROR;
+ }
else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
mSimState = IccCardConstants.State.READY;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 6ba18b3..79c63f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -106,7 +106,7 @@
@Override
public void onPanelPeeked() {
super.onPanelPeeked();
- mBar.makeExpandedVisible();
+ mBar.makeExpandedVisible(false);
}
@Override
@@ -160,6 +160,18 @@
}
@Override
+ public void onTrackingStarted(PanelView panel) {
+ super.onTrackingStarted(panel);
+ mBar.onTrackingStarted();
+ }
+
+ @Override
+ public void onTrackingStopped(PanelView panel) {
+ super.onTrackingStopped(panel);
+ mBar.onTrackingStopped();
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index c5dae85..6b5ef5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -69,8 +69,8 @@
mStackScrollLayout = (NotificationStackScrollLayout) findViewById(
R.id.notification_stack_scroller);
mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel);
- int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
- int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
+ int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
+ int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
mExpandHelper = new ExpandHelper(getContext(), mStackScrollLayout,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
index c1662ba..20011ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -212,6 +212,13 @@
}
}
+ @Override
+ protected void onDetachedFromWindow() {
+ if (mAdapter != null) {
+ mAdapter.dispose();
+ }
+ }
+
public void setAutoActivate(boolean value) {
mAutoActivate = value;
}
@@ -396,6 +403,7 @@
void setMode(boolean mode);
void select(ExitCondition ec);
void init();
+ void dispose();
void setCallbacks(Callbacks callbacks);
ExitCondition getExitCondition(int d);
int getExitConditionCount();
@@ -406,6 +414,7 @@
public String line1;
public String line2;
public String action;
+ public Object tag;
}
public interface Callbacks {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
index c97ba8d..a5e016a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
@@ -16,14 +16,22 @@
package com.android.systemui.statusbar.phone;
+import android.app.INotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.provider.Settings;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.util.ArrayMap;
import android.util.Log;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -34,8 +42,10 @@
private final ContentResolver mResolver;
private final Handler mHandler = new Handler();
private final SettingsObserver mObserver;
- private final List<ExitCondition> mExits = Arrays.asList(
- newExit("Until you turn this off", "Until", "You turn this off"));
+ private final List<ExitCondition> mExits = new ArrayList<ExitCondition>(Arrays.asList(
+ newExit("Until you turn this off", "Until", "You turn this off", null)));
+ private final INotificationManager mNoMan;
+ private final ArrayMap<Uri, Condition> mConditions = new ArrayMap<Uri, Condition>();
private Callbacks mCallbacks;
private int mExitIndex;
@@ -45,6 +55,13 @@
mContext = context;
mResolver = mContext.getContentResolver();
mObserver = new SettingsObserver(mHandler);
+ mNoMan = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ try {
+ mNoMan.requestZenModeConditions(mListener, true /*requested*/);
+ } catch (RemoteException e) {
+ // noop
+ }
mObserver.init();
init();
}
@@ -77,6 +94,15 @@
}
}
+ @Override
+ public void dispose() {
+ try {
+ mNoMan.requestZenModeConditions(mListener, false /*requested*/);
+ } catch (RemoteException e) {
+ // noop
+ }
+ }
+
private void dispatchChanged() {
mHandler.removeCallbacks(mChanged);
mHandler.post(mChanged);
@@ -117,13 +143,20 @@
}
mExitIndex = i;
dispatchChanged();
+ final Uri conditionUri = (Uri) ec.tag;
+ try {
+ mNoMan.setZenModeCondition(conditionUri);
+ } catch (RemoteException e) {
+ // noop
+ }
}
- private static ExitCondition newExit(String summary, String line1, String line2) {
+ private static ExitCondition newExit(String summary, String line1, String line2, Object tag) {
final ExitCondition rt = new ExitCondition();
rt.summary = summary;
rt.line1 = line1;
rt.line2 = line2;
+ rt.tag = tag;
return rt;
}
@@ -168,4 +201,21 @@
return v != Settings.Global.ZEN_MODE_OFF;
}
}
+
+ private final IConditionListener mListener = new IConditionListener.Stub() {
+ @Override
+ public void onConditionsReceived(Condition[] conditions) {
+ if (conditions == null || conditions.length == 0) return;
+ for (Condition c : conditions) {
+ mConditions.put(c.id, c);
+ }
+ for (int i = mExits.size() - 1; i > 0; i--) {
+ mExits.remove(i);
+ }
+ for (Condition c : mConditions.values()) {
+ mExits.add(newExit(c.caption, "", "", c.id));
+ }
+ dispatchChanged();
+ }
+ };
}
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 2dba669..c94c65f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -135,8 +135,8 @@
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop);
- int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
- int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
+ int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
+ int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
mExpandHelper = new ExpandHelper(getContext(), this, minHeight, maxHeight);
mContentHolder = (ViewGroup) findViewById(R.id.content_holder);
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 36d94a9..948ef90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -145,13 +145,13 @@
mSidePaddings = context.getResources()
.getDimensionPixelSize(R.dimen.notification_side_padding);
mCollapsedSize = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_row_min_height);
+ .getDimensionPixelSize(R.dimen.notification_min_height);
mBottomStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
mEmptyMarginBottom = context.getResources().getDimensionPixelSize(
R.dimen.notification_stack_margin_bottom);
- // currently the padding is in the elements themself
- mPaddingBetweenElements = 0;
+ mPaddingBetweenElements = context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_padding);
mStackScrollAlgorithm = new StackScrollAlgorithm(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index d9e7f66..2a6e4ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -62,11 +62,10 @@
}
private void initConstants(Context context) {
-
- // currently the padding is in the elements themself
- mPaddingBetweenElements = 0;
+ mPaddingBetweenElements = context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_padding);
mCollapsedSize = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_row_min_height);
+ .getDimensionPixelSize(R.dimen.notification_min_height);
mTopStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.top_stack_peek_amount);
mBottomStackPeekSize = context.getResources()
@@ -323,7 +322,8 @@
// the offset starting at the transitionPosition of the bottom stack
float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
- childViewState.yTranslation = transitioningPositionStart + offset - childHeight;
+ childViewState.yTranslation = transitioningPositionStart + offset - childHeight
+ - mPaddingBetweenElements;
// We want at least to be at the end of the top stack when collapsing
clampPositionToTopStackEnd(childViewState, childHeight);
@@ -339,7 +339,8 @@
if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
// We are visually entering the bottom stack
currentYPosition = transitioningPositionStart
- + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack);
+ + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
+ - mPaddingBetweenElements;
childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING;
} else {
// we are fully inside the stack
@@ -542,9 +543,13 @@
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight,
int oldBottom) {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(
- mFirstChildWhileExpanding);
- mFirstChildWhileExpanding.removeOnLayoutChangeListener(this);
+ if (mFirstChildWhileExpanding != null) {
+ mFirstChildMaxHeight = getMaxAllowedChildHeight(
+ mFirstChildWhileExpanding);
+ } else {
+ mFirstChildMaxHeight = 0;
+ }
+ v.removeOnLayoutChangeListener(this);
}
});
} else {
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 9742e65..6e2e87e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -197,18 +197,12 @@
* @param clipHeight the desired clip height, the rest of the view will be clipped from the top
*/
private void updateChildClip(View child, int height, float clipHeight) {
- // The children currently have paddings inside themselfs because of the expansion
- // visualization. In order for the clipping to work correctly we have to set the correct
- // clip rect on the child.
- View container = child.findViewById(R.id.container);
- if (container != null) {
- int clipInset = (int) (height - clipHeight);
- mClipRect.set(0,
- clipInset,
- child.getWidth(),
- height);
- child.setClipBounds(mClipRect);
- }
+ int clipInset = (int) (height - clipHeight);
+ mClipRect.set(0,
+ clipInset,
+ child.getWidth(),
+ height);
+ child.setClipBounds(mClipRect);
}
/**
@@ -218,22 +212,15 @@
* @param height the currently applied height of the view
* @param outlineHeight the desired height of the outline, the outline ends on the bottom
*/
- private void updateChildOutline(View child,
- int height,
- float outlineHeight) {
- // The children currently have paddings inside themselfs because of the expansion
- // visualization. In order for the shadows to work correctly we have to set the correct
- // outline on the child.
- View container = child.findViewById(R.id.container);
- if (container != null) {
- int shadowInset = (int) (height - outlineHeight);
- getOutlineForSize(container.getLeft(),
- container.getTop() + shadowInset,
- container.getWidth(),
- container.getHeight() - shadowInset,
- mChildOutline);
- child.setOutline(mChildOutline);
- }
+ private void updateChildOutline(View child, int height,
+ float outlineHeight) {
+ int shadowInset = (int) (height - outlineHeight);
+ getOutlineForSize(child.getLeft(),
+ child.getTop() + shadowInset,
+ child.getWidth(),
+ child.getHeight() - shadowInset,
+ mChildOutline);
+ child.setOutline(mChildOutline);
}
private void getOutlineForSize(int leftInset, int topInset, int width, int height,
diff --git a/services/Android.mk b/services/Android.mk
index 165f456..5fcef64 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -25,7 +25,8 @@
backup \
devicepolicy \
print \
- usb
+ usb \
+ voiceinteraction
# The convention is to name each service module 'services.$(module_name)'
LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 2f56e62..87b1d32 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -50,6 +50,7 @@
import android.os.UserHandle;
import android.util.AtomicFile;
import android.util.AttributeSet;
+import android.util.MutableInt;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -86,8 +87,6 @@
import java.util.Map.Entry;
import java.util.Set;
-import libcore.util.MutableInt;
-
class AppWidgetServiceImpl {
private static final String KEYGUARD_HOST_PACKAGE = "com.android.keyguard";
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 0b688b6..0082b1e 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -74,6 +74,8 @@
import android.os.Environment.UserEnvironment;
import android.os.storage.IMountService;
import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -142,9 +144,6 @@
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-
public class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
@@ -2471,7 +2470,7 @@
// operations any more during this pass).
Slog.w(TAG, "Unable to save widget state for " + pkgName);
try {
- Libcore.os.ftruncate(fd, filepos);
+ Os.ftruncate(fd, filepos);
} catch (ErrnoException ee) {
Slog.w(TAG, "Unable to roll back!");
}
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 62eb663..0d1e122 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -20,6 +20,7 @@
import android.net.LocalSocketAddress;
import android.os.Build;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -59,6 +60,8 @@
private final PowerManager.WakeLock mWakeLock;
+ private final Looper mLooper;
+
private INativeDaemonConnectorCallbacks mCallbacks;
private Handler mCallbackHandler;
@@ -74,6 +77,13 @@
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
+ this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl,
+ FgThread.get().getLooper());
+ }
+
+ NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
+ int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
+ Looper looper) {
mCallbacks = callbacks;
mSocket = socket;
mResponseQueue = new ResponseQueue(responseQueueSize);
@@ -81,6 +91,7 @@
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(true);
}
+ mLooper = looper;
mSequenceNumber = new AtomicInteger(0);
TAG = logTag != null ? logTag : "NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
@@ -88,7 +99,7 @@
@Override
public void run() {
- mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
+ mCallbackHandler = new Handler(mLooper, this);
while (true) {
try {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 705862a..7ce45f7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -58,6 +58,8 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.PhoneStateListener;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -143,21 +145,25 @@
public static final int InterfaceDnsServerInfo = 615;
}
+ static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
+
/**
* Binder context for this service
*/
- private Context mContext;
+ private final Context mContext;
/**
* connector object for communicating with netd
*/
- private NativeDaemonConnector mConnector;
+ private final NativeDaemonConnector mConnector;
private final Handler mFgHandler;
+ private final Handler mDaemonHandler;
+ private final PhoneStateListener mPhoneStateListener;
private IBatteryStats mBatteryStats;
- private Thread mThread;
+ private final Thread mThread;
private CountDownLatch mConnectedSignal = new CountDownLatch(1);
private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
@@ -191,6 +197,9 @@
private volatile boolean mBandwidthControlEnabled;
private volatile boolean mFirewallEnabled;
+ private boolean mMobileActivityFromRadio = false;
+ private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+
private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
new RemoteCallbackList<INetworkActivityListener>();
private boolean mNetworkActive;
@@ -207,20 +216,35 @@
mFgHandler = new Handler(FgThread.get().getLooper());
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ mConnector = null;
+ mThread = null;
+ mDaemonHandler = null;
+ mPhoneStateListener = null;
return;
}
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
// Don't need this wake lock, since we now have a time stamp for when
// the network actually went inactive. (It might be nice to still do this,
// but I don't want to do it through the power manager because that pollutes the
// battery stats history with pointless noise.)
+ //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
mConnector = new NativeDaemonConnector(
- new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl);
+ new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
+ FgThread.get().getLooper());
mThread = new Thread(mConnector, NETD_TAG);
+ mDaemonHandler = new Handler(FgThread.get().getLooper());
+ mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) {
+ public void onDataConnectionRealTimeInfoChanged(
+ DataConnectionRealTimeInfo dcRtInfo) {
+ // Disabled for now, until we are getting good data.
+ //notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
+ // dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
+ }
+ };
+
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
@@ -368,36 +392,62 @@
/**
* Notify our observers of a change in the data activity state of the interface
*/
- private void notifyInterfaceClassActivity(int type, boolean active, long tsNanos) {
- try {
- getBatteryStats().noteDataConnectionActive(type, active, tsNanos);
- } catch (RemoteException e) {
- }
-
- final int length = mObservers.beginBroadcast();
- try {
- for (int i = 0; i < length; i++) {
+ private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
+ boolean fromRadio) {
+ final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
+ if (isMobile) {
+ if (!fromRadio) {
+ if (mMobileActivityFromRadio) {
+ // If this call is not coming from a report from the radio itself, but we
+ // have previously received reports from the radio, then we will take the
+ // power state to just be whatever the radio last reported.
+ powerState = mLastPowerStateFromRadio;
+ }
+ } else {
+ mMobileActivityFromRadio = true;
+ }
+ if (mLastPowerStateFromRadio != powerState) {
+ mLastPowerStateFromRadio = powerState;
try {
- mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
- Integer.toString(type), active, tsNanos);
+ getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos);
} catch (RemoteException e) {
- } catch (RuntimeException e) {
}
}
- } finally {
- mObservers.finishBroadcast();
+ }
+
+ boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
+ || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+
+ if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
+ // Report the change in data activity. We don't do this if this is a change
+ // on the mobile network, that is not coming from the radio itself, and we
+ // have previously seen change reports from the radio. In that case only
+ // the radio is the authority for the current state.
+ final int length = mObservers.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
+ Integer.toString(type), isActive, tsNanos);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
+ }
+ } finally {
+ mObservers.finishBroadcast();
+ }
}
boolean report = false;
synchronized (mIdleTimerLock) {
if (mActiveIdleTimers.isEmpty()) {
- // If there are no idle times, we are not monitoring activity, so we
+ // If there are no idle timers, we are not monitoring activity, so we
// are always considered active.
- active = true;
+ isActive = true;
}
- if (mNetworkActive != active) {
- mNetworkActive = active;
- report = active;
+ if (mNetworkActive != isActive) {
+ mNetworkActive = isActive;
+ report = isActive;
}
}
if (report) {
@@ -611,10 +661,13 @@
try {
timestampNanos = Long.parseLong(cooked[4]);
} catch(NumberFormatException ne) {}
+ } else {
+ timestampNanos = SystemClock.elapsedRealtimeNanos();
}
boolean isActive = cooked[2].equals("active");
notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
- isActive, timestampNanos);
+ isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+ : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, timestampNanos, false);
return true;
// break;
case NetdResponseCode.InterfaceAddressChange:
@@ -1301,9 +1354,11 @@
if (ConnectivityManager.isNetworkTypeMobile(type)) {
mNetworkActive = false;
}
- mFgHandler.post(new Runnable() {
+ mDaemonHandler.post(new Runnable() {
@Override public void run() {
- notifyInterfaceClassActivity(type, true, SystemClock.elapsedRealtimeNanos());
+ notifyInterfaceClassActivity(type,
+ DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
+ SystemClock.elapsedRealtimeNanos(), false);
}
});
}
@@ -1328,10 +1383,11 @@
throw e.rethrowAsParcelableException();
}
mActiveIdleTimers.remove(iface);
- mFgHandler.post(new Runnable() {
+ mDaemonHandler.post(new Runnable() {
@Override public void run() {
- notifyInterfaceClassActivity(params.type, false,
- SystemClock.elapsedRealtimeNanos());
+ notifyInterfaceClassActivity(params.type,
+ DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
+ SystemClock.elapsedRealtimeNanos(), false);
}
});
}
@@ -1941,6 +1997,9 @@
pw.println();
pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
+ pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
+ pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
+ pw.print("mNetworkActive="); pw.println(mNetworkActive);
synchronized (mQuotaLock) {
pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index fa803e2..fe97c71 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -421,11 +421,8 @@
}
/* This goes in response as msg.arg2 */
- int clientId = -1;
- int keyId = clientInfo.mClientIds.indexOfValue(id);
- if (keyId != -1) {
- clientId = clientInfo.mClientIds.keyAt(keyId);
- } else {
+ int clientId = clientInfo.getClientId(id);
+ if (clientId < 0) {
// This can happen because of race conditions. For example,
// SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
// and we may get in this situation.
@@ -904,5 +901,18 @@
mClientRequests.clear();
}
+ // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id,
+ // return the corresponding listener id. mDnsClient id is also called a global id.
+ private int getClientId(final int globalId) {
+ // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals)
+ // while also coercing the int primitives to Integer objects.
+ for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) {
+ int mDnsId = mClientIds.valueAt(i);
+ if (globalId == mDnsId) {
+ return mClientIds.keyAt(i);
+ }
+ }
+ return -1;
+ }
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 037a744..d4565b6 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -393,6 +393,14 @@
if (!checkNotifyPermission("notifyServiceState()")){
return;
}
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.notePhoneState(state.getState());
+ } catch (RemoteException re) {
+ // Can't do much
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
synchronized (mRecords) {
mServiceState = state;
for (Record r : mRecords) {
@@ -802,15 +810,6 @@
//
private void broadcastServiceStateChanged(ServiceState state) {
- long ident = Binder.clearCallingIdentity();
- try {
- mBatteryStats.notePhoneState(state.getState());
- } catch (RemoteException re) {
- // Can't do much
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
Bundle data = new Bundle();
state.fillInNotifierBundle(data);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8fa076b..0c91907 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -28,19 +28,23 @@
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import android.Manifest;
import android.app.AppOpsManager;
import android.app.IActivityContainer;
import android.app.IActivityContainerCallback;
import android.appwidget.AppWidgetManager;
import android.graphics.Rect;
import android.os.BatteryStats;
+import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.ProcessStats;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
@@ -56,6 +60,7 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.firewall.IntentFirewall;
@@ -333,6 +338,9 @@
// How many bytes to write into the dropbox log before truncating
static final int DROPBOX_MAX_SIZE = 256 * 1024;
+ /** All system services */
+ SystemServiceManager mSystemServiceManager;
+
/** Run all ActivityStacks through this */
ActivityStackSupervisor mStackSupervisor;
@@ -399,7 +407,7 @@
/**
* List of intents that were used to start the most recent tasks.
*/
- private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
+ final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
public class PendingAssistExtras extends Binder implements Runnable {
public final ActivityRecord activity;
@@ -879,17 +887,23 @@
* Set while we are wanting to sleep, to prevent any
* activities from being started/resumed.
*/
- boolean mSleeping = false;
+ private boolean mSleeping = false;
+
+ /**
+ * Set while we are running a voice interaction. This overrides
+ * sleeping while it is active.
+ */
+ private boolean mRunningVoice = false;
/**
* State of external calls telling us if the device is asleep.
*/
- boolean mWentToSleep = false;
+ private boolean mWentToSleep = false;
/**
* State of external call telling us if the lock screen is shown.
*/
- boolean mLockScreenShown = false;
+ private boolean mLockScreenShown = false;
/**
* Set if we are shutting down the system, similar to sleeping.
@@ -1117,6 +1131,8 @@
static final int REQUEST_ALL_PSS_MSG = 39;
static final int START_PROFILES_MSG = 40;
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 FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1696,15 +1712,15 @@
break;
}
case REPORT_USER_SWITCH_MSG: {
- dispatchUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ dispatchUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
break;
}
case CONTINUE_USER_SWITCH_MSG: {
- continueUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ continueUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
break;
}
case USER_SWITCH_TIMEOUT_MSG: {
- timeoutUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ timeoutUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
break;
}
case IMMERSIVE_MODE_LOCK_MSG: {
@@ -1751,6 +1767,14 @@
}
break;
}
+ case SYSTEM_USER_START_MSG: {
+ mSystemServiceManager.startUser(msg.arg1);
+ break;
+ }
+ case SYSTEM_USER_CURRENT_MSG: {
+ mSystemServiceManager.switchUser(msg.arg1);
+ break;
+ }
}
}
};
@@ -1813,6 +1837,82 @@
}
};
+ /**
+ * Monitor for package changes and update our internal state.
+ */
+ private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ // Remove all tasks with activities in the specified package from the list of recent tasks
+ synchronized (ActivityManagerService.this) {
+ for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+ TaskRecord tr = mRecentTasks.get(i);
+ ComponentName cn = tr.intent.getComponent();
+ if (cn != null && cn.getPackageName().equals(packageName)) {
+ // If the package name matches, remove the task and kill the process
+ removeTaskByIdLocked(tr.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ final PackageManager pm = mContext.getPackageManager();
+ final ArrayList<Pair<Intent, Integer>> recentTaskIntents =
+ new ArrayList<Pair<Intent, Integer>>();
+ final ArrayList<Integer> tasksToRemove = new ArrayList<Integer>();
+ // Copy the list of recent tasks so that we don't hold onto the lock on
+ // ActivityManagerService for long periods while checking if components exist.
+ synchronized (ActivityManagerService.this) {
+ for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+ TaskRecord tr = mRecentTasks.get(i);
+ recentTaskIntents.add(new Pair<Intent, Integer>(tr.intent, tr.taskId));
+ }
+ }
+ // Check the recent tasks and filter out all tasks with components that no longer exist.
+ Intent tmpI = new Intent();
+ for (int i = recentTaskIntents.size() - 1; i >= 0; i--) {
+ Pair<Intent, Integer> p = recentTaskIntents.get(i);
+ ComponentName cn = p.first.getComponent();
+ if (cn != null && cn.getPackageName().equals(packageName)) {
+ try {
+ // Add the task to the list to remove if the component no longer exists
+ tmpI.setComponent(cn);
+ if (pm.queryIntentActivities(tmpI, PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
+ tasksToRemove.add(p.second);
+ }
+ } catch (Exception e) {}
+ }
+ }
+ // Prune all the tasks with removed components from the list of recent tasks
+ synchronized (ActivityManagerService.this) {
+ for (int i = tasksToRemove.size() - 1; i >= 0; i--) {
+ // Remove the task but don't kill the process (since other components in that
+ // package may still be running and in the background)
+ removeTaskByIdLocked(tasksToRemove.get(i), 0);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ // Force stop the specified packages
+ if (packages != null) {
+ for (String pkg : packages) {
+ synchronized (ActivityManagerService.this) {
+ if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0,
+ "finished booting")) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ };
+
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
@@ -2059,6 +2159,10 @@
Watchdog.getInstance().addThread(mHandler);
}
+ public void setSystemServiceManager(SystemServiceManager mgr) {
+ mSystemServiceManager = mgr;
+ }
+
private void start() {
mProcessCpuThread.start();
@@ -2254,6 +2358,11 @@
if (mFocusedActivity != r) {
if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivityLocked: r=" + r);
mFocusedActivity = r;
+ if (r.task != null && r.task.voiceInteractor != null) {
+ startRunningVoiceLocked();
+ } else {
+ finishRunningVoiceLocked();
+ }
mStackSupervisor.setFocusedStack(r);
if (r != null) {
mWindowManager.setFocusedApp(r.appToken, true);
@@ -2262,6 +2371,12 @@
}
}
+ final void clearFocusedActivity(ActivityRecord r) {
+ if (mFocusedActivity == r) {
+ mFocusedActivity = null;
+ }
+ }
+
@Override
public void setFocusedStack(int stackId) {
if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: stackId=" + stackId);
@@ -2990,7 +3105,7 @@
intent.setComponent(new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name));
mStackSupervisor.startActivityLocked(null, intent, null, ri.activityInfo,
- null, null, 0, 0, 0, null, 0, null, false, null, null);
+ null, null, null, null, 0, 0, 0, null, 0, null, false, null, null);
}
}
}
@@ -3121,7 +3236,7 @@
}
for (int i=0; i<N; i++) {
PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
- mStackSupervisor.startActivityUncheckedLocked(pal.r, pal.sourceRecord, pal.startFlags,
+ mStackSupervisor.startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
doResume && i == (N-1), null);
}
mPendingActivityLaunches.clear();
@@ -3147,7 +3262,7 @@
false, true, "startActivity", null);
// TODO: Switch to user app stacks here.
return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
+ null, null, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
null, null, options, userId, null);
}
@@ -3162,7 +3277,7 @@
WaitResult res = new WaitResult();
// TODO: Switch to user app stacks here.
mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
+ null, null, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
res, null, options, UserHandle.getCallingUserId(), null);
return res;
}
@@ -3177,7 +3292,7 @@
false, true, "startActivityWithConfig", null);
// TODO: Switch to user app stacks here.
int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, resultTo, resultWho, requestCode, startFlags,
+ resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
null, null, null, config, options, userId, null);
return ret;
}
@@ -3215,6 +3330,31 @@
}
@Override
+ public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
+ Intent intent, String resolvedType, IVoiceInteractionSession session,
+ IVoiceInteractor interactor, int startFlags, String profileFile,
+ ParcelFileDescriptor profileFd, Bundle options, int userId) {
+ if (checkCallingPermission(Manifest.permission.BIND_VOICE_INTERACTION)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: startVoiceActivity() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.BIND_VOICE_INTERACTION;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ if (session == null || interactor == null) {
+ throw new NullPointerException("null session or interactor");
+ }
+ userId = handleIncomingUser(callingPid, callingUid, userId,
+ false, true, "startVoiceActivity", null);
+ // TODO: Switch to user app stacks here.
+ return mStackSupervisor.startActivityMayWait(null, callingUid, callingPackage, intent,
+ resolvedType, session, interactor, null, null, 0, startFlags,
+ profileFile, profileFd, null, null, options, userId, null);
+ }
+
+ @Override
public boolean startNextMatchingActivity(IBinder callingActivity,
Intent intent, Bundle options) {
// Refuse possible leaked file descriptors
@@ -3307,7 +3447,7 @@
final long origId = Binder.clearCallingIdentity();
int res = mStackSupervisor.startActivityLocked(r.app.thread, intent,
- r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null,
+ r.resolvedType, aInfo, null, null, resultTo != null ? resultTo.appToken : null,
resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage, 0,
options, false, null, null);
Binder.restoreCallingIdentity(origId);
@@ -3330,7 +3470,7 @@
// TODO: Switch to user app stacks here.
int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags,
+ null, null, resultTo, resultWho, requestCode, startFlags,
null, null, null, null, options, userId, container);
return ret;
}
@@ -3366,6 +3506,10 @@
if (N > 0 && mRecentTasks.get(0) == task) {
return;
}
+ // Another quick case: never add voice sessions.
+ if (task.voiceSession != null) {
+ return;
+ }
// Remove any existing entries that are the same kind of task.
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
@@ -5200,26 +5344,8 @@
}
final void finishBooting() {
- IntentFilter pkgFilter = new IntentFilter();
- pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
- pkgFilter.addDataScheme("package");
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
- if (pkgs != null) {
- for (String pkg : pkgs) {
- synchronized (ActivityManagerService.this) {
- if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0,
- "finished booting")) {
- setResultCode(Activity.RESULT_OK);
- return;
- }
- }
- }
- }
- }
- }, pkgFilter);
+ // Register receivers to handle package update events
+ mPackageMonitor.register(mContext, Looper.getMainLooper(), false);
synchronized (this) {
// Ensure that any processes we had put on hold are now started
@@ -8509,11 +8635,27 @@
return mSleeping || mShuttingDown;
}
+ public boolean isSleeping() {
+ return mSleeping;
+ }
+
void goingToSleep() {
synchronized(this) {
mWentToSleep = true;
updateEventDispatchingLocked();
+ goToSleepIfNeededLocked();
+ }
+ }
+ void finishRunningVoiceLocked() {
+ if (mRunningVoice) {
+ mRunningVoice = false;
+ goToSleepIfNeededLocked();
+ }
+ }
+
+ void goToSleepIfNeededLocked() {
+ if (mWentToSleep && !mRunningVoice) {
if (!mSleeping) {
mSleeping = true;
mStackSupervisor.goingToSleepLocked();
@@ -8576,7 +8718,7 @@
}
private void comeOutOfSleepIfNeededLocked() {
- if (!mWentToSleep && !mLockScreenShown) {
+ if ((!mWentToSleep && !mLockScreenShown) || mRunningVoice) {
if (mSleeping) {
mSleeping = false;
mStackSupervisor.comeOutOfSleepIfNeededLocked();
@@ -8592,6 +8734,13 @@
}
}
+ void startRunningVoiceLocked() {
+ if (!mRunningVoice) {
+ mRunningVoice = true;
+ comeOutOfSleepIfNeededLocked();
+ }
+ }
+
private void updateEventDispatchingLocked() {
mWindowManager.setEventDispatching(mBooted && !mWentToSleep && !mShuttingDown);
}
@@ -9298,7 +9447,7 @@
proc.notCachedSinceIdle = true;
proc.initialIdlePss = 0;
proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true,
- mSleeping, now);
+ isSleeping(), now);
}
}
@@ -9597,6 +9746,8 @@
if (goingCallback != null) goingCallback.run();
+ mSystemServiceManager.startUser(mCurrentUserId);
+
synchronized (this) {
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
try {
@@ -9653,6 +9804,8 @@
}, 0, null, null,
android.Manifest.permission.INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ } catch (Throwable t) {
+ Slog.wtf(TAG, "Failed sending first user broadcasts", t);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -11152,8 +11305,8 @@
pw.println(" mSleeping=" + mSleeping + " mWentToSleep=" + mWentToSleep
+ " mLockScreenShown " + mLockScreenShown);
}
- if (mShuttingDown) {
- pw.println(" mShuttingDown=" + mShuttingDown);
+ if (mShuttingDown || mRunningVoice) {
+ pw.print(" mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
}
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
@@ -15273,7 +15426,7 @@
if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
app.pssProcState = app.setProcState;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
- mSleeping, now);
+ isSleeping(), now);
mPendingPssProcesses.add(app);
}
}
@@ -15310,7 +15463,7 @@
}
}
return !processingBroadcasts
- && (mSleeping || mStackSupervisor.allResumedActivitiesIdle());
+ && (isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
}
/**
@@ -15585,7 +15738,7 @@
app.setProcState)) {
app.lastStateTime = now;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
- mSleeping, now);
+ isSleeping(), now);
if (DEBUG_PSS) Slog.d(TAG, "Process state change from "
+ ProcessList.makeProcStateString(app.setProcState) + " to "
+ ProcessList.makeProcStateString(app.curProcState) + " next pss in "
@@ -15595,7 +15748,7 @@
&& now > (app.lastStateTime+ProcessList.PSS_MIN_TIME_FROM_STATE_CHANGE))) {
requestPssLocked(app, app.setProcState);
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
- mSleeping, now);
+ isSleeping(), now);
} else if (false && DEBUG_PSS) {
Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
}
@@ -15932,7 +16085,7 @@
}
mLastMemoryLevel = memFactor;
mLastNumProcesses = mLruProcesses.size();
- boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !mSleeping, now);
+ boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleeping(), now);
final int trackerMemFactor = mProcessStats.getMemFactorLocked();
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
@@ -16369,7 +16522,8 @@
* background.
*/
private void updateCurrentProfileIdsLocked() {
- final List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+ final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+ mCurrentUserId, false /* enabledOnly */);
int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
for (int i = 0; i < currentProfileIds.length; i++) {
currentProfileIds[i] = profiles.get(i).id;
@@ -16379,7 +16533,8 @@
private Set getProfileIdsLocked(int userId) {
Set userIds = new HashSet<Integer>();
- final List<UserInfo> profiles = getUserManagerLocked().getProfiles(userId);
+ final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+ userId, false /* enabledOnly */);
for (UserInfo user : profiles) {
userIds.add(Integer.valueOf(user.id));
}
@@ -16473,7 +16628,15 @@
needStart = true;
}
+ if (uss.mState == UserStartedState.STATE_BOOTING) {
+ // Booting up a new user, need to tell system services about it.
+ // Note that this is on the same handler as scheduling of broadcasts,
+ // which is important because it needs to go first.
+ mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId));
+ }
+
if (foreground) {
+ mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId));
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
@@ -16678,7 +16841,8 @@
void startProfilesLocked() {
if (DEBUG_MU) Slog.i(TAG_MU, "startProfilesLocked");
- List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+ List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+ mCurrentUserId, false /* enabledOnly */);
List<UserInfo> toStart = new ArrayList<UserInfo>(profiles.size());
for (UserInfo user : profiles) {
if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
@@ -16827,6 +16991,7 @@
}
uss.mState = UserStartedState.STATE_SHUTDOWN;
}
+ mSystemServiceManager.stopUser(userId);
broadcastIntentLocked(null, null, shutdownIntent,
null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
true, false, MY_PID, Process.SYSTEM_UID, userId);
@@ -16876,7 +17041,12 @@
}
}
- mStackSupervisor.removeUserLocked(userId);
+ if (stopped) {
+ mSystemServiceManager.cleanupUser(userId);
+ synchronized (this) {
+ mStackSupervisor.removeUserLocked(userId);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 3e59def..7a44473 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -633,7 +633,7 @@
// case we will deliver it if this is the current top activity on its
// stack.
boolean unsent = true;
- if ((state == ActivityState.RESUMED || (service.mSleeping
+ if ((state == ActivityState.RESUMED || (service.isSleeping()
&& task.stack.topRunningActivityLocked(null) == this))
&& app != null && app.thread != null) {
try {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0acde09..6769c9c 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -38,6 +38,8 @@
import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE;
+import android.service.voice.IVoiceInteractionSession;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
@@ -501,6 +503,11 @@
if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
+ if (task.voiceSession != null) {
+ // We never match voice sessions; those always run independently.
+ if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": voice session");
+ continue;
+ }
if (task.userId != userId) {
// Looking for a different task.
if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": different user");
@@ -735,7 +742,9 @@
int w = mThumbnailWidth;
int h = mThumbnailHeight;
if (w < 0) {
- if (SystemProperties.getBoolean("persist.recents.use_alternate", false)) {
+ Configuration config = res.getConfiguration();
+ boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
+ if (useAlternateRecents) {
mThumbnailWidth = w =
res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
mThumbnailHeight = h =
@@ -793,7 +802,7 @@
prev.task.touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
- if (next == null || next.task != prev.task) {
+ if (next == null || next.noDisplay || next.task != prev.task) {
prev.updateThumbnail(screenshotActivities(prev), null);
}
stopFullyDrawnTraceIfNeeded();
@@ -1501,7 +1510,7 @@
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
- if (mService.mSleeping && mLastNoHistoryActivity != null &&
+ if (mService.isSleeping() && mLastNoHistoryActivity != null &&
!mLastNoHistoryActivity.finishing) {
if (DEBUG_STATES) Slog.d(TAG, "no-history finish of " + mLastNoHistoryActivity +
" on new resume");
@@ -2032,7 +2041,7 @@
+ " out to bottom task " + bottom.task);
} else {
targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
- null, false);
+ null, null, null, false);
newThumbHolder = targetTask;
targetTask.affinityIntent = target.intent;
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
@@ -2320,7 +2329,10 @@
mStackSupervisor.moveHomeToTop();
}
}
- mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked());
+ ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+ if (top != null) {
+ mService.setFocusedActivityLocked(top);
+ }
}
}
@@ -2329,7 +2341,7 @@
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
- if (!mService.mSleeping) {
+ if (!mService.isSleeping()) {
if (DEBUG_STATES) {
Slog.d(TAG, "no-history finish of " + r);
}
@@ -2708,7 +2720,7 @@
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
destIntent.getComponent(), 0, srec.userId);
int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent,
- null, aInfo, parent.appToken, null,
+ null, aInfo, null, null, parent.appToken, null,
0, -1, parent.launchedFromUid, parent.launchedFromPackage,
0, null, true, null, null);
foundParentInTask = res == ActivityManager.START_SUCCESS;
@@ -2737,9 +2749,7 @@
if (mPausingActivity == r) {
mPausingActivity = null;
}
- if (mService.mFocusedActivity == r) {
- mService.mFocusedActivity = null;
- }
+ mService.clearFocusedActivity(r);
r.configDestroy = false;
r.frozenBeforeDestroy = false;
@@ -3721,6 +3731,11 @@
mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
}
mTaskHistory.remove(task);
+ if (task.voiceInteractor != null) {
+ // This task was a voice interaction, so it should not remain on the
+ // recent tasks list.
+ mService.mRecentTasks.remove(task);
+ }
if (mTaskHistory.isEmpty()) {
if (DEBUG_STACK) Slog.i(TAG, "removeTask: moving to back stack=" + this);
@@ -3734,8 +3749,10 @@
}
}
- TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, boolean toTop) {
- TaskRecord task = new TaskRecord(taskId, info, intent);
+ TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ boolean toTop) {
+ TaskRecord task = new TaskRecord(taskId, info, intent, voiceSession, voiceInteractor);
addTask(task, toTop);
return task;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index afef4ff..3770a07 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import static android.Manifest.permission.START_ANY_ACTIVITY;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -77,6 +76,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -87,6 +87,7 @@
import android.view.InputEvent;
import android.view.Surface;
import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.TransferPipe;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
@@ -687,13 +688,14 @@
void startHomeActivity(Intent intent, ActivityInfo aInfo) {
moveHomeToTop();
- startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0,
+ startActivityLocked(null, intent, null, aInfo, null, null, null, null, 0, 0, 0, null, 0,
null, false, null, null);
}
final int startActivityMayWait(IApplicationThread caller, int callingUid,
- String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int startFlags, String profileFile,
+ String callingPackage, Intent intent, String resolvedType,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile,
ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
Bundle options, int userId, IActivityContainer iContainer) {
// Refuse possible leaked file descriptors
@@ -802,7 +804,8 @@
}
}
- int res = startActivityLocked(caller, intent, resolvedType, aInfo, resultTo, resultWho,
+ int res = startActivityLocked(caller, intent, resolvedType, aInfo,
+ voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage, startFlags, options,
componentSpecified, null, container);
@@ -918,7 +921,7 @@
theseOptions = null;
}
int res = startActivityLocked(caller, intent, resolvedTypes[i],
- aInfo, resultTo, null, -1, callingPid, callingUid, callingPackage,
+ aInfo, null, null, resultTo, null, -1, callingPid, callingUid, callingPackage,
0, theseOptions, componentSpecified, outActivity, null);
if (res < 0) {
return res;
@@ -1034,8 +1037,8 @@
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
new Configuration(mService.mConfiguration), r.compat,
- app.repProcState, r.icicle, results, newIntents, !andResume,
- mService.isNextTransitionForward(), profileFile, profileFd,
+ r.task.voiceInteractor, app.repProcState, r.icicle, results, newIntents,
+ !andResume, mService.isNextTransitionForward(), profileFile, profileFd,
profileAutoStop, options);
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
@@ -1143,8 +1146,9 @@
}
final int startActivityLocked(IApplicationThread caller,
- Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
- String resultWho, int requestCode,
+ Intent intent, String resolvedType, ActivityInfo aInfo,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ IBinder resultTo, String resultWho, int requestCode,
int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container) {
int err = ActivityManager.START_SUCCESS;
@@ -1187,7 +1191,7 @@
}
ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
- int launchFlags = intent.getFlags();
+ final int launchFlags = intent.getFlags();
if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
&& sourceRecord != null) {
@@ -1232,6 +1236,38 @@
err = ActivityManager.START_CLASS_NOT_FOUND;
}
+ if (err == ActivityManager.START_SUCCESS && sourceRecord != null
+ && sourceRecord.task.voiceSession != null) {
+ // If this activity is being launched as part of a voice session, we need
+ // to ensure that it is safe to do so. If the upcoming activity will also
+ // be part of the voice session, we can only launch it if it has explicitly
+ // said it supports the VOICE category, or it is a part of the calling app.
+ if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
+ && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
+ try {
+ if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
+ intent, resolvedType)) {
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ } catch (RemoteException e) {
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ }
+ }
+
+ if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
+ // If the caller is starting a new voice session, just make sure the target
+ // is actually allowing it to run this way.
+ try {
+ if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
+ intent, resolvedType)) {
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ } catch (RemoteException e) {
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ }
+
if (err != ActivityManager.START_SUCCESS) {
if (resultRecord != null) {
resultStack.sendActivityResultLocked(-1,
@@ -1305,8 +1341,8 @@
}
final ActivityStack stack = getFocusedStack();
- if (stack.mResumedActivity == null
- || stack.mResumedActivity.info.applicationInfo.uid != callingUid) {
+ if (voiceSession == null && (stack.mResumedActivity == null
+ || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
PendingActivityLaunch pal =
new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
@@ -1330,7 +1366,8 @@
mService.doPendingActivityLaunchesLocked(false);
- err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);
+ err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
+ startFlags, true, options);
if (allPausedActivitiesComplete()) {
// If someone asked to have the keyguard dismissed on the next
@@ -1410,8 +1447,9 @@
}
final int startActivityUncheckedLocked(ActivityRecord r,
- ActivityRecord sourceRecord, int startFlags, boolean doResume,
- Bundle options) {
+ ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
+ boolean doResume, Bundle options) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
@@ -1755,7 +1793,7 @@
r.setTask(targetStack.createTaskRecord(getNextTaskId(),
newTaskInfo != null ? newTaskInfo : r.info,
newTaskIntent != null ? newTaskIntent : intent,
- true), null, true);
+ voiceSession, voiceInteractor, true), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
r.task);
} else {
@@ -1833,7 +1871,7 @@
targetStack.moveToFront();
ActivityRecord prev = targetStack.topActivity();
r.setTask(prev != null ? prev.task
- : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
+ : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, null, null, true),
null, true);
mWindowManager.moveTaskToTop(r.task.taskId);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
@@ -3000,6 +3038,8 @@
}
class ActivityContainer extends android.app.IActivityContainer.Stub {
+ final static int FORCE_NEW_TASK_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
final int mStackId;
IActivityContainerCallback mCallback = null;
final ActivityStack mStack;
@@ -3096,12 +3136,13 @@
int userId = mService.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
// TODO: Switch to user app stacks here.
+ intent.addFlags(FORCE_NEW_TASK_FLAGS);
String mimeType = intent.getType();
if (mimeType == null && intent.getData() != null
&& "content".equals(intent.getData().getScheme())) {
mimeType = mService.getProviderMimeType(intent.getData(), userId);
}
- return startActivityMayWait(null, -1, null, intent, mimeType, null, null, 0, 0, null,
+ return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null, 0, 0, null,
null, null, null, null, userId, this);
}
@@ -3114,7 +3155,41 @@
}
return ((PendingIntentRecord)intentSender).sendInner(0, null, null, null, null, null,
- null, 0, 0, 0, null, this);
+ null, 0, FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
+ }
+
+ private void checkEmbeddedAllowedInner(Intent intent, String resolvedType) {
+ int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
+ if (resolvedType == null) {
+ resolvedType = intent.getType();
+ if (resolvedType == null && intent.getData() != null
+ && "content".equals(intent.getData().getScheme())) {
+ resolvedType = mService.getProviderMimeType(intent.getData(), userId);
+ }
+ }
+ ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, null, userId);
+ if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+ throw new SecurityException(
+ "Attempt to embed activity that has not set allowEmbedded=\"true\"");
+ }
+ }
+
+ /** Throw a SecurityException if allowEmbedded is not true */
+ @Override
+ public final void checkEmbeddedAllowed(Intent intent) {
+ checkEmbeddedAllowedInner(intent, null);
+ }
+
+ /** Throw a SecurityException if allowEmbedded is not true */
+ @Override
+ public final void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
+ if (!(intentSender instanceof PendingIntentRecord)) {
+ throw new IllegalArgumentException("Bad PendingIntent object");
+ }
+ PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender;
+ checkEmbeddedAllowedInner(pendingIntent.key.requestIntent,
+ pendingIntent.key.requestResolvedType);
}
@Override
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 0ddb827..dbe773c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -32,6 +32,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Slog;
@@ -248,10 +249,10 @@
}
}
- public void noteDataConnectionActive(int type, boolean active, long timestampNs) {
+ public void noteMobileRadioPowerState(int powerState, long timestampNs) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteDataConnectionActive(type, active, timestampNs);
+ mStats.noteMobileRadioPowerState(powerState, timestampNs);
}
}
diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
index 443218c..d42d415 100644
--- a/services/core/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -17,14 +17,13 @@
package com.android.server.am;
import android.app.ApplicationErrorReport.CrashInfo;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructTimeval;
+import android.system.StructUcred;
import android.util.Slog;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.StructTimeval;
-import libcore.io.StructUcred;
-
-import static libcore.io.OsConstants.*;
+import static android.system.OsConstants.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -77,7 +76,7 @@
try {
CrashInfo ci = new CrashInfo();
ci.exceptionClassName = "Native crash";
- ci.exceptionMessage = Libcore.os.strsignal(mSignal);
+ ci.exceptionMessage = Os.strsignal(mSignal);
ci.throwFileName = "unknown";
ci.throwClassName = "unknown";
ci.throwMethodName = "unknown";
@@ -117,22 +116,22 @@
}
try {
- FileDescriptor serverFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
+ FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
final InetUnixAddress sockAddr = new InetUnixAddress(DEBUGGERD_SOCKET_PATH);
- Libcore.os.bind(serverFd, sockAddr, 0);
- Libcore.os.listen(serverFd, 1);
+ Os.bind(serverFd, sockAddr, 0);
+ Os.listen(serverFd, 1);
while (true) {
InetSocketAddress peer = new InetSocketAddress();
FileDescriptor peerFd = null;
try {
if (MORE_DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
- peerFd = Libcore.os.accept(serverFd, peer);
+ peerFd = Os.accept(serverFd, peer);
if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
if (peerFd != null) {
// Only the superuser is allowed to talk to us over this socket
StructUcred credentials =
- Libcore.os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
+ Os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
if (credentials.uid == 0) {
// the reporting thread may take responsibility for
// acking the debugger; make sure we play along.
@@ -146,7 +145,7 @@
// byte written is irrelevant.
if (peerFd != null) {
try {
- Libcore.os.write(peerFd, ackSignal, 0, 1);
+ Os.write(peerFd, ackSignal, 0, 1);
} catch (Exception e) {
/* we don't care about failures here */
if (MORE_DEBUG) {
@@ -154,7 +153,7 @@
}
}
try {
- Libcore.os.close(peerFd);
+ Os.close(peerFd);
} catch (ErrnoException e) {
if (MORE_DEBUG) {
Slog.d(TAG, "Exception closing socket: " + e.getMessage());
@@ -182,7 +181,7 @@
throws ErrnoException, InterruptedIOException {
int totalRead = 0;
while (numBytes > 0) {
- int n = Libcore.os.read(fd, buffer, offset + totalRead, numBytes);
+ int n = Os.read(fd, buffer, offset + totalRead, numBytes);
if (n <= 0) {
if (DEBUG) {
Slog.w(TAG, "Needed " + numBytes + " but saw " + n);
@@ -203,8 +202,8 @@
try {
StructTimeval timeout = StructTimeval.fromMillis(SOCKET_TIMEOUT_MILLIS);
- Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
- Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);
// first, the pid and signal number
int headerBytes = readExactly(fd, buf, 0, 8);
@@ -238,7 +237,7 @@
int bytes;
do {
// get some data
- bytes = Libcore.os.read(fd, buf, 0, buf.length);
+ bytes = Os.read(fd, buf, 0, buf.length);
if (bytes > 0) {
if (MORE_DEBUG) {
String s = new String(buf, 0, bytes, "UTF-8");
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 80a219dd..68da54d 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -28,7 +28,9 @@
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
import android.util.Slog;
+import com.android.internal.app.IVoiceInteractor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -36,6 +38,8 @@
final class TaskRecord extends ThumbnailHolder {
final int taskId; // Unique identifier for this task.
final String affinity; // The affinity name for this task, or null.
+ final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
+ final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
Intent intent; // The original intent that started the task.
Intent affinityIntent; // Intent of affinity-moved activity that started this task.
ComponentName origActivity; // The non-alias activity component of the intent.
@@ -64,9 +68,12 @@
* Display.DEFAULT_DISPLAY. */
boolean mOnTopOfHome = false;
- TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
+ TaskRecord(int _taskId, ActivityInfo info, Intent _intent,
+ IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
taskId = _taskId;
affinity = info.taskAffinity;
+ voiceSession = _voiceSession;
+ voiceInteractor = _voiceInteractor;
setIntent(_intent, info);
}
@@ -473,6 +480,12 @@
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);
}
+ if (voiceSession != null || voiceInteractor != null) {
+ pw.print(prefix); pw.print("VOICE: session=0x");
+ pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
+ pw.print(" interactor=0x");
+ pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
+ }
if (intent != null) {
StringBuilder sb = new StringBuilder(128);
sb.append(prefix); sb.append("intent={");
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
new file mode 100644
index 0000000..5f07108
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -0,0 +1,94 @@
+/*
+ * 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 android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
+ * and pass it to CEC HAL so that it sends message to other device. For incoming
+ * message it translates the message and delegates it to proper module.
+ *
+ * <p>It can be created only by {@link HdmiCecController#create}
+ *
+ * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
+ */
+class HdmiCecController {
+ private static final String TAG = "HdmiCecController";
+
+ // Handler instance to process synchronous I/O (mainly send) message.
+ private Handler mIoHandler;
+
+ // Handler instance to process various messages coming from other CEC
+ // device or issued by internal state change.
+ private Handler mMessageHandler;
+
+ // Stores the pointer to the native implementation of the service that
+ // interacts with HAL.
+ private long mNativePtr;
+
+ // Private constructor. Use HdmiCecController.create().
+ private HdmiCecController() {
+ }
+
+ /**
+ * A factory method to get {@link HdmiCecController}. If it fails to initialize
+ * inner device or has no device it will return {@code null}.
+ *
+ * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
+ *
+ * @param ioLooper a Looper instance to handle IO (mainly send message) operation.
+ * @param messageHandler a message handler that processes a message coming from other
+ * CEC compatible device or callback of internal state change.
+ * @return {@link HdmiCecController} if device is initialized successfully. Otherwise,
+ * returns {@code null}.
+ */
+ static HdmiCecController create(Looper ioLooper, Handler messageHandler) {
+ HdmiCecController handler = new HdmiCecController();
+ long nativePtr = nativeInit(handler);
+ if (nativePtr == 0L) {
+ handler = null;
+ return null;
+ }
+
+ handler.init(ioLooper, messageHandler, nativePtr);
+ return handler;
+ }
+
+ private void init(Looper ioLooper, Handler messageHandler, long nativePtr) {
+ mIoHandler = new Handler(ioLooper) {
+ @Override
+ public void handleMessage(Message msg) {
+ // TODO: Call native sendMessage.
+ }
+ };
+
+ mMessageHandler = messageHandler;
+ mNativePtr = nativePtr;
+ }
+
+ /**
+ * Called by native when an HDMI-CEC message arrived.
+ */
+ private void handleMessage(int srcAddress, int dstAddres, int opcode, byte[] params) {
+ // TODO: Translate message and delegate it to main message handler.
+ }
+
+ private static native long nativeInit(HdmiCecController handler);
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
new file mode 100644
index 0000000..56c5b49
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.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.server.hdmi;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+/**
+ * Provides a service for sending and processing HDMI control messages,
+ * HDMI-CEC and MHL control command, and providing the information on both standard.
+ */
+public final class HdmiControlService extends SystemService {
+ private static final String TAG = "HdmiControlService";
+
+ // A thread to handle synchronous IO of CEC and MHL control service.
+ // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms)
+ // and sparse call it shares a thread to handle IO operations.
+ private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread");
+
+ // Main handler class to handle incoming message from each controller.
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ // TODO: Add handler for each message type.
+ }
+ };
+
+ @Nullable
+ private HdmiCecController mCecController;
+
+ @Nullable
+ private HdmiMhlController mMhlController;
+
+ public HdmiControlService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mCecController = HdmiCecController.create(mIoThread.getLooper(), mHandler);
+ if (mCecController == null) {
+ Slog.i(TAG, "Device does not support HDMI-CEC.");
+ }
+
+ mMhlController = HdmiMhlController.create(mIoThread.getLooper(), mHandler);
+ if (mMhlController == null) {
+ Slog.i(TAG, "Device does not support MHL-control.");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
index fab84a8..79f192d 100644
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java
@@ -60,6 +60,10 @@
private static final int FLP_RESULT_ID_UNKNOWN = -5;
private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6;
+ // FlpHal monitor status codes, they must be equal to the ones in fused_location.h
+ private static final int FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE = 1<<0;
+ private static final int FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE = 1<<1;
+
public static FlpHardwareProvider getInstance(Context context) {
if (sSingletonInstance == null) {
sSingletonInstance = new FlpHardwareProvider(context);
@@ -141,6 +145,8 @@
int transition,
long timestamp,
int sourcesUsed) {
+ // the transition Id does not require translation because the values in fused_location.h
+ // and GeofenceHardware are in sync
getGeofenceHardwareSink().reportGeofenceTransition(
geofenceId,
updateLocationInformation(location),
@@ -157,9 +163,23 @@
updatedLocation = updateLocationInformation(location);
}
+ int monitorStatus;
+ switch (status) {
+ case FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE:
+ monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
+ break;
+ case FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE:
+ monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
+ break;
+ default:
+ Log.e(TAG, "Invalid FlpHal Geofence monitor status: " + status);
+ monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
+ break;
+ }
+
getGeofenceHardwareSink().reportGeofenceMonitorStatus(
GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
- status,
+ monitorStatus,
updatedLocation,
source);
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
new file mode 100644
index 0000000..29af433
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -0,0 +1,257 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import libcore.util.Objects;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+public class ConditionProviders extends ManagedServices {
+
+ private final ZenModeHelper mZenModeHelper;
+ private final ArrayMap<IBinder, IConditionListener> mListeners
+ = new ArrayMap<IBinder, IConditionListener>();
+ private final ArrayMap<Uri, ManagedServiceInfo> mConditions
+ = new ArrayMap<Uri, ManagedServiceInfo>();
+
+ private Uri mCurrentConditionId;
+
+ public ConditionProviders(Context context, Handler handler,
+ UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
+ super(context, handler, new Object(), userProfiles);
+ mZenModeHelper = zenModeHelper;
+ mZenModeHelper.addCallback(new ZenModeHelperCallback());
+ }
+
+ @Override
+ protected Config getConfig() {
+ Config c = new Config();
+ c.caption = "condition provider";
+ c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
+ c.secureSettingName = Settings.Secure.ENABLED_CONDITION_PROVIDERS;
+ c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
+ c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS;
+ c.clientLabel = R.string.condition_provider_service_binding_label;
+ return c;
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ super.dump(pw);
+ synchronized(mMutex) {
+ pw.print(" mCurrentConditionId="); pw.println(mCurrentConditionId);
+ pw.print(" mListeners("); pw.print(mListeners.size()); pw.println("):");
+ for (int i = 0; i < mListeners.size(); i++) {
+ pw.print(" "); pw.println(mListeners.keyAt(i));
+ }
+ pw.print(" mConditions("); pw.print(mConditions.size()); pw.println("):");
+ for (int i = 0; i < mConditions.size(); i++) {
+ pw.print(" "); pw.print(mConditions.keyAt(i));
+ final ManagedServiceInfo info = mConditions.valueAt(i);
+ pw.print(" -> "); pw.print(info.component);
+ if (!mServices.contains(info)) {
+ pw.print(" (orphan)");
+ }
+ pw.println();
+ }
+ }
+ }
+
+ @Override
+ protected IInterface asInterface(IBinder binder) {
+ return IConditionProvider.Stub.asInterface(binder);
+ }
+
+ @Override
+ protected void onServiceAdded(IInterface service) {
+ Slog.d(TAG, "onServiceAdded " + service);
+ final IConditionProvider provider = (IConditionProvider) service;
+ try {
+ provider.onConnected();
+ } catch (RemoteException e) {
+ // we tried
+ }
+ }
+
+ @Override
+ protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
+ if (removed == null) return;
+ for (int i = mConditions.size() - 1; i >= 0; i--) {
+ if (removed.equals(mConditions.valueAt(i))) {
+ mConditions.removeAt(i);
+ }
+ }
+ }
+
+ public ManagedServiceInfo checkServiceToken(IConditionProvider provider) {
+ synchronized(mMutex) {
+ return checkServiceTokenLocked(provider);
+ }
+ }
+
+ public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback
+ + " requested=" + requested);
+ if (callback == null) return;
+ if (requested) {
+ mListeners.put(callback.asBinder(), callback);
+ requestConditionsLocked(Condition.FLAG_RELEVANT_NOW);
+ } else {
+ mListeners.remove(callback.asBinder());
+ if (mListeners.isEmpty()) {
+ requestConditionsLocked(0);
+ }
+ }
+ }
+ }
+
+ public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions="
+ + (conditions == null ? null : Arrays.asList(conditions)));
+ if (conditions == null || conditions.length == 0) return;
+ final int N = conditions.length;
+ boolean valid = true;
+ for (int i = 0; i < N; i++) {
+ final Uri id = conditions[i].id;
+ if (!Condition.isValidId(id, pkg)) {
+ Slog.w(TAG, "Ignoring conditions from " + pkg + " for invalid id: " + id);
+ valid = false;
+ }
+ }
+ if (!valid) return;
+
+ for (int i = 0; i < N; i++) {
+ mConditions.put(conditions[i].id, info);
+ }
+ for (IConditionListener listener : mListeners.values()) {
+ try {
+ listener.onConditionsReceived(conditions);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error sending conditions to listener " + listener, e);
+ }
+ }
+ if (mCurrentConditionId != null) {
+ for (int i = 0; i < N; i++) {
+ final Condition c = conditions[i];
+ if (!c.id.equals(mCurrentConditionId)) continue;
+ if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_ERROR) {
+ triggerExitLocked(c.state == Condition.STATE_ERROR);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private void triggerExitLocked(boolean error) {
+ if (error) {
+ Slog.w(TAG, "Zen mode exit condition failed");
+ } else if (DEBUG) {
+ Slog.d(TAG, "Zen mode exit condition triggered");
+ }
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ unsubscribeLocked(mCurrentConditionId);
+ mCurrentConditionId = null;
+ }
+
+ public void setZenModeCondition(Uri conditionId) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
+ if (Objects.equal(mCurrentConditionId, conditionId)) return;
+
+ if (mCurrentConditionId != null) {
+ unsubscribeLocked(mCurrentConditionId);
+ }
+ if (conditionId != null) {
+ final ManagedServiceInfo info = mConditions.get(conditionId);
+ final IConditionProvider provider = provider(info);
+ if (provider == null) return;
+ try {
+ provider.onSubscribe(conditionId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error subscribing to " + conditionId
+ + " from " + info.component, e);
+ }
+ }
+ mCurrentConditionId = conditionId;
+ }
+ }
+
+ private void unsubscribeLocked(Uri conditionId) {
+ final ManagedServiceInfo info = mConditions.get(mCurrentConditionId);
+ final IConditionProvider provider = provider(info);
+ if (provider == null) return;
+ try {
+ provider.onUnsubscribe(conditionId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, e);
+ }
+ }
+
+ private static IConditionProvider provider(ManagedServiceInfo info) {
+ return info == null ? null : (IConditionProvider) info.service;
+ }
+
+ private void requestConditionsLocked(int flags) {
+ for (ManagedServiceInfo info : mServices) {
+ final IConditionProvider provider = provider(info);
+ if (provider == null) continue;
+ try {
+ provider.onRequestConditions(flags);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error requesting conditions from " + info.component, e);
+ }
+ }
+ }
+
+ private class ZenModeHelperCallback extends ZenModeHelper.Callback {
+ @Override
+ void onZenModeChanged() {
+ final int mode = mZenModeHelper.getZenMode();
+ if (mode == Global.ZEN_MODE_OFF) {
+ synchronized (mMutex) {
+ if (mCurrentConditionId != null) {
+ if (DEBUG) Slog.d(TAG, "Zen mode off, forcing unsubscribe from "
+ + mCurrentConditionId);
+ unsubscribeLocked(mCurrentConditionId);
+ mCurrentConditionId = null;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
new file mode 100644
index 0000000..0621f58
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -0,0 +1,621 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Manages the lifecycle of application-provided services bound by system server.
+ *
+ * Services managed by this helper must have:
+ * - An associated system settings value with a list of enabled component names.
+ * - A well-known action for services to use in their intent-filter.
+ * - A system permission for services to require in order to ensure system has exclusive binding.
+ * - A settings page for user configuration of enabled services, and associated intent action.
+ * - A remote interface definition (aidl) provided by the service used for communication.
+ */
+abstract public class ManagedServices {
+ protected final String TAG = getClass().getSimpleName();
+ protected static final boolean DEBUG = true;
+
+ private static final String ENABLED_SERVICES_SEPARATOR = ":";
+
+ private final Context mContext;
+ protected final Object mMutex;
+ private final UserProfiles mUserProfiles;
+ private final SettingsObserver mSettingsObserver;
+ private final Config mConfig;
+
+ // contains connections to all connected services, including app services
+ // and system services
+ protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
+ // things that will be put into mServices as soon as they're ready
+ private final ArrayList<String> mServicesBinding = new ArrayList<String>();
+ // lists the component names of all enabled (and therefore connected)
+ // app services for current profiles.
+ private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
+ = new ArraySet<ComponentName>();
+ // Just the packages from mEnabledServicesForCurrentProfiles
+ private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<String>();
+
+ public ManagedServices(Context context, Handler handler, Object mutex,
+ UserProfiles userProfiles) {
+ mContext = context;
+ mMutex = mutex;
+ mUserProfiles = userProfiles;
+ mConfig = getConfig();
+ mSettingsObserver = new SettingsObserver(handler);
+ }
+
+ abstract protected Config getConfig();
+
+ private String getCaption() {
+ return mConfig.caption;
+ }
+
+ abstract protected IInterface asInterface(IBinder binder);
+
+ abstract protected void onServiceAdded(IInterface service);
+
+ protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
+
+ private ManagedServiceInfo newServiceInfo(IInterface service,
+ ComponentName component, int userid, boolean isSystem, ServiceConnection connection,
+ int targetSdkVersion) {
+ return new ManagedServiceInfo(service, component, userid, isSystem, connection,
+ targetSdkVersion);
+ }
+
+ public void onBootPhaseAppsCanStart() {
+ mSettingsObserver.observe();
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
+ + ") enabled for current profiles:");
+ for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
+ pw.println(" " + cmpt);
+ }
+
+ pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
+ for (ManagedServiceInfo info : mServices) {
+ pw.println(" " + info.component
+ + " (user " + info.userid + "): " + info.service
+ + (info.isSystem?" SYSTEM":""));
+ }
+ }
+
+ public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
+ if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
+ + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
+ + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
+ boolean anyServicesInvolved = false;
+ if (pkgList != null && (pkgList.length > 0)) {
+ for (String pkgName : pkgList) {
+ if (mEnabledServicesPackageNames.contains(pkgName)) {
+ anyServicesInvolved = true;
+ }
+ }
+ }
+
+ if (anyServicesInvolved) {
+ // if we're not replacing a package, clean up orphaned bits
+ if (!queryReplace) {
+ disableNonexistentServices();
+ }
+ // make sure we're still bound to any of our services who may have just upgraded
+ rebindServices();
+ }
+ }
+
+ public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
+ checkNotNull(service);
+ final IBinder token = service.asBinder();
+ final int N = mServices.size();
+ for (int i=0; i<N; i++) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (info.service.asBinder() == token) return info;
+ }
+ throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
+ + service);
+ }
+
+ public void unregisterService(IInterface service, int userid) {
+ checkNotNull(service);
+ // no need to check permissions; if your service binder is in the list,
+ // that's proof that you had permission to add it in the first place
+ unregisterServiceImpl(service, userid);
+ }
+
+ public void registerService(IInterface service, ComponentName component, int userid) {
+ checkNotNull(service);
+ registerServiceImpl(service, component, userid);
+ }
+
+ /**
+ * Remove access for any services that no longer exist.
+ */
+ private void disableNonexistentServices() {
+ int[] userIds = mUserProfiles.getCurrentProfileIds();
+ final int N = userIds.length;
+ for (int i = 0 ; i < N; ++i) {
+ disableNonexistentServices(userIds[i]);
+ }
+ }
+
+ private void disableNonexistentServices(int userId) {
+ String flatIn = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ mConfig.secureSettingName,
+ userId);
+ if (!TextUtils.isEmpty(flatIn)) {
+ if (DEBUG) Slog.v(TAG, "flat before: " + flatIn);
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
+ new Intent(mConfig.serviceInterface),
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+ userId);
+ if (DEBUG) Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
+ Set<ComponentName> installed = new ArraySet<ComponentName>();
+ for (int i = 0, count = installedServices.size(); i < count; i++) {
+ ResolveInfo resolveInfo = installedServices.get(i);
+ ServiceInfo info = resolveInfo.serviceInfo;
+
+ if (!mConfig.bindPermission.equals(info.permission)) {
+ Slog.w(TAG, "Skipping " + getCaption() + " service "
+ + info.packageName + "/" + info.name
+ + ": it does not require the permission "
+ + mConfig.bindPermission);
+ continue;
+ }
+ installed.add(new ComponentName(info.packageName, info.name));
+ }
+
+ String flatOut = "";
+ if (!installed.isEmpty()) {
+ String[] enabled = flatIn.split(ENABLED_SERVICES_SEPARATOR);
+ ArrayList<String> remaining = new ArrayList<String>(enabled.length);
+ for (int i = 0; i < enabled.length; i++) {
+ ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]);
+ if (installed.contains(enabledComponent)) {
+ remaining.add(enabled[i]);
+ }
+ }
+ flatOut = TextUtils.join(ENABLED_SERVICES_SEPARATOR, remaining);
+ }
+ if (DEBUG) Slog.v(TAG, "flat after: " + flatOut);
+ if (!flatIn.equals(flatOut)) {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ mConfig.secureSettingName,
+ flatOut, userId);
+ }
+ }
+ }
+
+ /**
+ * Called whenever packages change, the user switches, or the secure setting
+ * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
+ */
+ private void rebindServices() {
+ if (DEBUG) Slog.d(TAG, "rebindServices");
+ final int[] userIds = mUserProfiles.getCurrentProfileIds();
+ final int nUserIds = userIds.length;
+
+ final SparseArray<String> flat = new SparseArray<String>();
+
+ for (int i = 0; i < nUserIds; ++i) {
+ flat.put(userIds[i], Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ mConfig.secureSettingName,
+ userIds[i]));
+ }
+
+ ManagedServiceInfo[] toRemove = new ManagedServiceInfo[mServices.size()];
+ final SparseArray<ArrayList<ComponentName>> toAdd
+ = new SparseArray<ArrayList<ComponentName>>();
+
+ synchronized (mMutex) {
+ // unbind and remove all existing services
+ toRemove = mServices.toArray(toRemove);
+
+ final ArraySet<ComponentName> newEnabled = new ArraySet<ComponentName>();
+ final ArraySet<String> newPackages = new ArraySet<String>();
+
+ for (int i = 0; i < nUserIds; ++i) {
+ final ArrayList<ComponentName> add = new ArrayList<ComponentName>();
+ toAdd.put(userIds[i], add);
+
+ // decode the list of components
+ String toDecode = flat.get(userIds[i]);
+ if (toDecode != null) {
+ String[] components = toDecode.split(ENABLED_SERVICES_SEPARATOR);
+ for (int j = 0; j < components.length; j++) {
+ final ComponentName component
+ = ComponentName.unflattenFromString(components[j]);
+ if (component != null) {
+ newEnabled.add(component);
+ add.add(component);
+ newPackages.add(component.getPackageName());
+ }
+ }
+
+ }
+ }
+ mEnabledServicesForCurrentProfiles = newEnabled;
+ mEnabledServicesPackageNames = newPackages;
+ }
+
+ for (ManagedServiceInfo info : toRemove) {
+ final ComponentName component = info.component;
+ final int oldUser = info.userid;
+ Slog.v(TAG, "disabling " + getCaption() + " for user "
+ + oldUser + ": " + component);
+ unregisterService(component, info.userid);
+ }
+
+ for (int i = 0; i < nUserIds; ++i) {
+ final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
+ final int N = add.size();
+ for (int j = 0; j < N; j++) {
+ final ComponentName component = add.get(j);
+ Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
+ + component);
+ registerService(component, userIds[i]);
+ }
+ }
+ }
+
+ /**
+ * Version of registerService that takes the name of a service component to bind to.
+ */
+ private void registerService(final ComponentName name, final int userid) {
+ if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
+
+ synchronized (mMutex) {
+ final String servicesBindingTag = name.toString() + "/" + userid;
+ if (mServicesBinding.contains(servicesBindingTag)) {
+ // stop registering this thing already! we're working on it
+ return;
+ }
+ mServicesBinding.add(servicesBindingTag);
+
+ final int N = mServices.size();
+ for (int i=N-1; i>=0; i--) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (name.equals(info.component)
+ && info.userid == userid) {
+ // cut old connections
+ if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
+ + info.service);
+ removeServiceLocked(i);
+ if (info.connection != null) {
+ mContext.unbindService(info.connection);
+ }
+ }
+ }
+
+ Intent intent = new Intent(mConfig.serviceInterface);
+ intent.setComponent(name);
+
+ intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
+
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ mContext, 0, new Intent(mConfig.settingsAction), 0);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
+
+ ApplicationInfo appInfo = null;
+ try {
+ appInfo = mContext.getPackageManager().getApplicationInfo(
+ name.getPackageName(), 0);
+ } catch (NameNotFoundException e) {
+ // Ignore if the package doesn't exist we won't be able to bind to the service.
+ }
+ final int targetSdkVersion =
+ appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
+
+ try {
+ if (DEBUG) Slog.v(TAG, "binding: " + intent);
+ if (!mContext.bindServiceAsUser(intent,
+ new ServiceConnection() {
+ IInterface mService;
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder binder) {
+ boolean added = false;
+ synchronized (mMutex) {
+ mServicesBinding.remove(servicesBindingTag);
+ try {
+ mService = asInterface(binder);
+ ManagedServiceInfo info = newServiceInfo(mService, name,
+ userid, false /*isSystem*/, this, targetSdkVersion);
+ binder.linkToDeath(info, 0);
+ added = mServices.add(info);
+ } catch (RemoteException e) {
+ // already dead
+ }
+ }
+ if (added) {
+ onServiceAdded(mService);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Slog.v(TAG, getCaption() + " connection lost: " + name);
+ }
+ },
+ Context.BIND_AUTO_CREATE,
+ new UserHandle(userid)))
+ {
+ mServicesBinding.remove(servicesBindingTag);
+ Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
+ return;
+ }
+ } catch (SecurityException ex) {
+ Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Remove a service for the given user by ComponentName
+ */
+ private void unregisterService(ComponentName name, int userid) {
+ synchronized (mMutex) {
+ final int N = mServices.size();
+ for (int i=N-1; i>=0; i--) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (name.equals(info.component)
+ && info.userid == userid) {
+ removeServiceLocked(i);
+ if (info.connection != null) {
+ try {
+ mContext.unbindService(info.connection);
+ } catch (IllegalArgumentException ex) {
+ // something happened to the service: we think we have a connection
+ // but it's bogus.
+ Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a service from the list but does not unbind
+ *
+ * @return the removed service.
+ */
+ private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
+ if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
+ ManagedServiceInfo serviceInfo = null;
+ synchronized (mMutex) {
+ final int N = mServices.size();
+ for (int i=N-1; i>=0; i--) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (info.service.asBinder() == service.asBinder()
+ && info.userid == userid) {
+ if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
+ serviceInfo = removeServiceLocked(i);
+ }
+ }
+ }
+ return serviceInfo;
+ }
+
+ private ManagedServiceInfo removeServiceLocked(int i) {
+ final ManagedServiceInfo info = mServices.remove(i);
+ onServiceRemovedLocked(info);
+ return info;
+ }
+
+ private void checkNotNull(IInterface service) {
+ if (service == null) {
+ throw new IllegalArgumentException(getCaption() + " must not be null");
+ }
+ }
+
+ private void registerServiceImpl(final IInterface service,
+ final ComponentName component, final int userid) {
+ synchronized (mMutex) {
+ try {
+ ManagedServiceInfo info = newServiceInfo(service, component, userid,
+ true /*isSystem*/, null, Build.VERSION_CODES.L);
+ service.asBinder().linkToDeath(info, 0);
+ mServices.add(info);
+ } catch (RemoteException e) {
+ // already dead
+ }
+ }
+ }
+
+ /**
+ * Removes a service from the list and unbinds.
+ */
+ private void unregisterServiceImpl(IInterface service, int userid) {
+ ManagedServiceInfo info = removeServiceImpl(service, userid);
+ if (info != null && info.connection != null) {
+ mContext.unbindService(info.connection);
+ }
+ }
+
+ private class SettingsObserver extends ContentObserver {
+ private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
+
+ private SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ private void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(mSecureSettingsUri,
+ false, this, UserHandle.USER_ALL);
+ update(null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update(uri);
+ }
+
+ private void update(Uri uri) {
+ if (uri == null || mSecureSettingsUri.equals(uri)) {
+ rebindServices();
+ }
+ }
+ }
+
+ public class ManagedServiceInfo implements IBinder.DeathRecipient {
+ public IInterface service;
+ public ComponentName component;
+ public int userid;
+ public boolean isSystem;
+ public ServiceConnection connection;
+ public int targetSdkVersion;
+
+ public ManagedServiceInfo(IInterface service, ComponentName component,
+ int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
+ this.service = service;
+ this.component = component;
+ this.userid = userid;
+ this.isSystem = isSystem;
+ this.connection = connection;
+ this.targetSdkVersion = targetSdkVersion;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("ManagedServiceInfo[")
+ .append("component=").append(component)
+ .append(",userid=").append(userid)
+ .append(",isSystem=").append(isSystem)
+ .append(",targetSdkVersion=").append(targetSdkVersion)
+ .append(",connection=").append(connection == null ? null : "<connection>")
+ .append(",service=").append(service)
+ .append(']').toString();
+ }
+
+ public boolean enabledAndUserMatches(int nid) {
+ if (!isEnabledForCurrentProfiles()) {
+ return false;
+ }
+ if (this.userid == UserHandle.USER_ALL) return true;
+ if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
+ return supportsProfiles() && mUserProfiles.isCurrentProfile(nid);
+ }
+
+ public boolean supportsProfiles() {
+ return targetSdkVersion >= Build.VERSION_CODES.L;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) Slog.d(TAG, "binderDied");
+ // Remove the service, but don't unbind from the service. The system will bring the
+ // service back up, and the onServiceConnected handler will readd the service with the
+ // new binding. If this isn't a bound service, and is just a registered
+ // service, just removing it from the list is all we need to do anyway.
+ removeServiceImpl(this.service, this.userid);
+ }
+
+ /** convenience method for looking in mEnabledServicesForCurrentProfiles */
+ public boolean isEnabledForCurrentProfiles() {
+ if (this.isSystem) return true;
+ if (this.connection == null) return false;
+ return mEnabledServicesForCurrentProfiles.contains(this.component);
+ }
+ }
+
+ public static class UserProfiles {
+ // Profiles of the current user.
+ private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
+
+ public void updateCache(Context context) {
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ if (userManager != null) {
+ int currentUserId = ActivityManager.getCurrentUser();
+ List<UserInfo> profiles = userManager.getProfiles(currentUserId);
+ synchronized (mCurrentProfiles) {
+ mCurrentProfiles.clear();
+ for (UserInfo user : profiles) {
+ mCurrentProfiles.put(user.id, user);
+ }
+ }
+ }
+ }
+
+ public int[] getCurrentProfileIds() {
+ synchronized (mCurrentProfiles) {
+ int[] users = new int[mCurrentProfiles.size()];
+ final int N = mCurrentProfiles.size();
+ for (int i = 0; i < N; ++i) {
+ users[i] = mCurrentProfiles.keyAt(i);
+ }
+ return users;
+ }
+ }
+
+ public boolean isCurrentProfile(int userId) {
+ synchronized (mCurrentProfiles) {
+ return mCurrentProfiles.get(userId) != null;
+ }
+ }
+ }
+
+ protected static class Config {
+ String caption;
+ String serviceInterface;
+ String secureSettingName;
+ String bindPermission;
+ String settingsAction;
+ int clientLabel;
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c8bdb4c..6e4eb565 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -36,14 +36,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -51,20 +47,22 @@
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IInterface;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.INotificationListener;
+import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
+import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -72,7 +70,6 @@
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -82,11 +79,15 @@
import com.android.internal.notification.NotificationScorer;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.EventLogTags;
-import com.android.server.notification.NotificationUsageStats.SingleNotificationStats;
-import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.SystemService;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+import com.android.server.notification.ManagedServices.ManagedServiceInfo;
+import com.android.server.notification.ManagedServices.UserProfiles;
+import com.android.server.notification.NotificationUsageStats.SingleNotificationStats;
+import com.android.server.statusbar.StatusBarManagerInternal;
+
+import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -105,11 +106,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.NoSuchElementException;
-import java.util.Set;
-
-import libcore.io.IoUtils;
/** {@hide} */
public class NotificationManagerService extends SystemService {
@@ -143,8 +140,6 @@
static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
static final boolean ENABLE_BLOCKED_TOASTS = true;
- static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
-
private IActivityManager mAm;
AudioManager mAudioManager;
StatusBarManagerInternal mStatusBar;
@@ -185,19 +180,6 @@
private AppOpsManager mAppOps;
- // contains connections to all connected listeners, including app services
- // and system listeners
- private ArrayList<NotificationListenerInfo> mListeners
- = new ArrayList<NotificationListenerInfo>();
- // things that will be put into mListeners as soon as they're ready
- private ArrayList<String> mServicesBinding = new ArrayList<String>();
- // lists the component names of all enabled (and therefore connected) listener
- // app services for current profiles.
- private HashSet<ComponentName> mEnabledListenersForCurrentProfiles
- = new HashSet<ComponentName>();
- // Just the packages from mEnabledListenersForCurrentProfiles
- private HashSet<String> mEnabledListenerPackageNames = new HashSet<String>();
-
// Notification control database. For now just contains disabled packages.
private AtomicFile mPolicyFile;
private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -213,13 +195,14 @@
final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+ private final UserProfiles mUserProfiles = new UserProfiles();
+ private NotificationListeners mListeners;
+ private ConditionProviders mConditionProviders;
+
private final NotificationUsageStats mUsageStats = new NotificationUsageStats();
private static final String EXTRA_INTERCEPT = "android.intercept";
- // Profiles of the current user.
- final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
-
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
private static final int REASON_DELEGATE_CLICK = 1;
@@ -234,85 +217,6 @@
private static final int REASON_LISTENER_CANCEL = 10;
private static final int REASON_LISTENER_CANCEL_ALL = 11;
- private class NotificationListenerInfo implements IBinder.DeathRecipient {
- INotificationListener listener;
- ComponentName component;
- int userid;
- boolean isSystem;
- ServiceConnection connection;
- int targetSdkVersion;
-
- public NotificationListenerInfo(INotificationListener listener, ComponentName component,
- int userid, boolean isSystem, int targetSdkVersion) {
- this.listener = listener;
- this.component = component;
- this.userid = userid;
- this.isSystem = isSystem;
- this.connection = null;
- this.targetSdkVersion = targetSdkVersion;
- }
-
- public NotificationListenerInfo(INotificationListener listener, ComponentName component,
- int userid, ServiceConnection connection, int targetSdkVersion) {
- this.listener = listener;
- this.component = component;
- this.userid = userid;
- this.isSystem = false;
- this.connection = connection;
- this.targetSdkVersion = targetSdkVersion;
- }
-
- boolean enabledAndUserMatches(StatusBarNotification sbn) {
- final int nid = sbn.getUserId();
- if (!isEnabledForCurrentProfiles()) {
- return false;
- }
- if (this.userid == UserHandle.USER_ALL) return true;
- if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
- return supportsProfiles() && isCurrentProfile(nid);
- }
-
- boolean supportsProfiles() {
- return targetSdkVersion >= Build.VERSION_CODES.L;
- }
-
- public void notifyPostedIfUserMatch(StatusBarNotification sbn) {
- if (!enabledAndUserMatches(sbn)) {
- return;
- }
- try {
- listener.onNotificationPosted(sbn);
- } catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
- }
- }
-
- public void notifyRemovedIfUserMatch(StatusBarNotification sbn) {
- if (!enabledAndUserMatches(sbn)) return;
- try {
- listener.onNotificationRemoved(sbn);
- } catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
- }
- }
-
- @Override
- public void binderDied() {
- // Remove the listener, but don't unbind from the service. The system will bring the
- // service back up, and the onServiceConnected handler will readd the listener with the
- // new binding. If this isn't a bound service, and is just a registered
- // INotificationListener, just removing it from the list is all we need to do anyway.
- removeListenerImpl(this.listener, this.userid);
- }
-
- /** convenience method for looking in mEnabledListenersForCurrentProfiles */
- public boolean isEnabledForCurrentProfiles() {
- if (this.isSystem) return true;
- if (this.connection == null) return false;
- return mEnabledListenersForCurrentProfiles.contains(this.component);
- }
- }
-
private static class Archive {
static final int BUFFER_SIZE = 250;
ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
@@ -537,328 +441,6 @@
}
- /**
- * Remove notification access for any services that no longer exist.
- */
- void disableNonexistentListeners() {
- int[] userIds = getCurrentProfileIds();
- final int N = userIds.length;
- for (int i = 0 ; i < N; ++i) {
- disableNonexistentListeners(userIds[i]);
- }
- }
-
- void disableNonexistentListeners(int userId) {
- String flatIn = Settings.Secure.getStringForUser(
- getContext().getContentResolver(),
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- userId);
- if (!TextUtils.isEmpty(flatIn)) {
- if (DBG) Slog.v(TAG, "flat before: " + flatIn);
- PackageManager pm = getContext().getPackageManager();
- List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
- new Intent(NotificationListenerService.SERVICE_INTERFACE),
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
- userId);
-
- Set<ComponentName> installed = new HashSet<ComponentName>();
- for (int i = 0, count = installedServices.size(); i < count; i++) {
- ResolveInfo resolveInfo = installedServices.get(i);
- ServiceInfo info = resolveInfo.serviceInfo;
-
- if (!android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE.equals(
- info.permission)) {
- Slog.w(TAG, "Skipping notification listener service "
- + info.packageName + "/" + info.name
- + ": it does not require the permission "
- + android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
- continue;
- }
- installed.add(new ComponentName(info.packageName, info.name));
- }
-
- String flatOut = "";
- if (!installed.isEmpty()) {
- String[] enabled = flatIn.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR);
- ArrayList<String> remaining = new ArrayList<String>(enabled.length);
- for (int i = 0; i < enabled.length; i++) {
- ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]);
- if (installed.contains(enabledComponent)) {
- remaining.add(enabled[i]);
- }
- }
- flatOut = TextUtils.join(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR, remaining);
- }
- if (DBG) Slog.v(TAG, "flat after: " + flatOut);
- if (!flatIn.equals(flatOut)) {
- Settings.Secure.putStringForUser(getContext().getContentResolver(),
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- flatOut, userId);
- }
- }
- }
-
- /**
- * Called whenever packages change, the user switches, or ENABLED_NOTIFICATION_LISTENERS
- * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
- */
- void rebindListenerServices() {
- final int[] userIds = getCurrentProfileIds();
- final int nUserIds = userIds.length;
-
- final SparseArray<String> flat = new SparseArray<String>();
-
- for (int i = 0; i < nUserIds; ++i) {
- flat.put(userIds[i], Settings.Secure.getStringForUser(
- getContext().getContentResolver(),
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- userIds[i]));
- }
-
- NotificationListenerInfo[] toRemove = new NotificationListenerInfo[mListeners.size()];
- final SparseArray<ArrayList<ComponentName>> toAdd
- = new SparseArray<ArrayList<ComponentName>>();
-
- synchronized (mNotificationList) {
- // unbind and remove all existing listeners
- toRemove = mListeners.toArray(toRemove);
-
- final HashSet<ComponentName> newEnabled = new HashSet<ComponentName>();
- final HashSet<String> newPackages = new HashSet<String>();
-
- for (int i = 0; i < nUserIds; ++i) {
- final ArrayList<ComponentName> add = new ArrayList<ComponentName>();
- toAdd.put(userIds[i], add);
-
- // decode the list of components
- String toDecode = flat.get(userIds[i]);
- if (toDecode != null) {
- String[] components = toDecode.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR);
- for (int j = 0; j < components.length; j++) {
- final ComponentName component
- = ComponentName.unflattenFromString(components[j]);
- if (component != null) {
- newEnabled.add(component);
- add.add(component);
- newPackages.add(component.getPackageName());
- }
- }
-
- }
- }
- mEnabledListenersForCurrentProfiles = newEnabled;
- mEnabledListenerPackageNames = newPackages;
- }
-
- for (NotificationListenerInfo info : toRemove) {
- final ComponentName component = info.component;
- final int oldUser = info.userid;
- Slog.v(TAG, "disabling notification listener for user "
- + oldUser + ": " + component);
- unregisterListenerService(component, info.userid);
- }
-
- for (int i = 0; i < nUserIds; ++i) {
- final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
- final int N = add.size();
- for (int j = 0; j < N; j++) {
- final ComponentName component = add.get(j);
- Slog.v(TAG, "enabling notification listener for user " + userIds[i] + ": "
- + component);
- registerListenerService(component, userIds[i]);
- }
- }
- }
-
-
- /**
- * Version of registerListener that takes the name of a
- * {@link android.service.notification.NotificationListenerService} to bind to.
- *
- * This is the mechanism by which third parties may subscribe to notifications.
- */
- private void registerListenerService(final ComponentName name, final int userid) {
- checkCallerIsSystem();
-
- if (DBG) Slog.v(TAG, "registerListenerService: " + name + " u=" + userid);
-
- synchronized (mNotificationList) {
- final String servicesBindingTag = name.toString() + "/" + userid;
- if (mServicesBinding.contains(servicesBindingTag)) {
- // stop registering this thing already! we're working on it
- return;
- }
- mServicesBinding.add(servicesBindingTag);
-
- final int N = mListeners.size();
- for (int i=N-1; i>=0; i--) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (name.equals(info.component)
- && info.userid == userid) {
- // cut old connections
- if (DBG) Slog.v(TAG, " disconnecting old listener: " + info.listener);
- mListeners.remove(i);
- if (info.connection != null) {
- getContext().unbindService(info.connection);
- }
- }
- }
-
- Intent intent = new Intent(NotificationListenerService.SERVICE_INTERFACE);
- intent.setComponent(name);
-
- intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
- R.string.notification_listener_binding_label);
-
- final PendingIntent pendingIntent = PendingIntent.getActivity(
- getContext(), 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0);
- intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
-
- ApplicationInfo appInfo = null;
- try {
- appInfo = getContext().getPackageManager().getApplicationInfo(
- name.getPackageName(), 0);
- } catch (NameNotFoundException e) {
- // Ignore if the package doesn't exist we won't be able to bind to the service.
- }
- final int targetSdkVersion =
- appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
-
- try {
- if (DBG) Slog.v(TAG, "binding: " + intent);
- if (!getContext().bindServiceAsUser(intent,
- new ServiceConnection() {
- INotificationListener mListener;
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- boolean added = false;
- synchronized (mNotificationList) {
- mServicesBinding.remove(servicesBindingTag);
- try {
- mListener = INotificationListener.Stub.asInterface(service);
- NotificationListenerInfo info
- = new NotificationListenerInfo(
- mListener, name, userid, this,
- targetSdkVersion);
- service.linkToDeath(info, 0);
- added = mListeners.add(info);
- } catch (RemoteException e) {
- // already dead
- }
- }
- if (added) {
- final String[] keys =
- getActiveNotificationKeysFromListener(mListener);
- try {
- mListener.onListenerConnected(keys);
- } catch (RemoteException e) {
- // we tried
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Slog.v(TAG, "notification listener connection lost: " + name);
- }
- },
- Context.BIND_AUTO_CREATE,
- new UserHandle(userid)))
- {
- mServicesBinding.remove(servicesBindingTag);
- Slog.w(TAG, "Unable to bind listener service: " + intent);
- return;
- }
- } catch (SecurityException ex) {
- Slog.e(TAG, "Unable to bind listener service: " + intent, ex);
- return;
- }
- }
- }
-
-
- /**
- * Remove a listener service for the given user by ComponentName
- */
- private void unregisterListenerService(ComponentName name, int userid) {
- checkCallerIsSystem();
-
- synchronized (mNotificationList) {
- final int N = mListeners.size();
- for (int i=N-1; i>=0; i--) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (name.equals(info.component)
- && info.userid == userid) {
- mListeners.remove(i);
- if (info.connection != null) {
- try {
- getContext().unbindService(info.connection);
- } catch (IllegalArgumentException ex) {
- // something happened to the service: we think we have a connection
- // but it's bogus.
- Slog.e(TAG, "Listener " + name + " could not be unbound: " + ex);
- }
- }
- }
- }
- }
- }
-
- /**
- * asynchronously notify all listeners about a new notification
- */
- void notifyPostedLocked(NotificationRecord n) {
- // make a copy in case changes are made to the underlying Notification object
- final StatusBarNotification sbn = n.sbn.clone();
- for (final NotificationListenerInfo info : mListeners) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- info.notifyPostedIfUserMatch(sbn);
- }});
- }
- }
-
- /**
- * asynchronously notify all listeners about a removed notification
- */
- void notifyRemovedLocked(NotificationRecord n) {
- // make a copy in case changes are made to the underlying Notification object
- // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the notification
- final StatusBarNotification sbn_light = n.sbn.cloneLight();
-
- for (final NotificationListenerInfo info : mListeners) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- info.notifyRemovedIfUserMatch(sbn_light);
- }});
- }
- }
-
- // -- APIs to support listeners clicking/clearing notifications --
-
- private void checkNullListener(INotificationListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("Listener must not be null");
- }
- }
-
- private NotificationListenerInfo checkListenerTokenLocked(INotificationListener listener) {
- checkNullListener(listener);
- final IBinder token = listener.asBinder();
- final int N = mListeners.size();
- for (int i=0; i<N; i++) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (info.listener.asBinder() == token) return info;
- }
- throw new SecurityException("Disallowed call from unknown listener: " + listener);
- }
-
-
-
- // -- end of listener APIs --
public static final class NotificationRecord
{
@@ -1125,7 +707,7 @@
String pkgList[] = null;
boolean queryReplace = queryRemove &&
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- if (DBG) Slog.i(TAG, "queryReplace=" + queryReplace);
+ if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
} else if (queryRestart) {
@@ -1159,28 +741,16 @@
pkgList = new String[]{pkgName};
}
- boolean anyListenersInvolved = false;
if (pkgList != null && (pkgList.length > 0)) {
for (String pkgName : pkgList) {
if (cancelNotifications) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null);
}
- if (mEnabledListenerPackageNames.contains(pkgName)) {
- anyListenersInvolved = true;
- }
}
}
-
- if (anyListenersInvolved) {
- // if we're not replacing a package, clean up orphaned bits
- if (!queryReplace) {
- disableNonexistentListeners();
- }
- // make sure we're still bound to any of our
- // listeners who may have just upgraded
- rebindListenerServices();
- }
+ mListeners.onPackagesChanged(queryReplace, pkgList);
+ mConditionProviders.onPackagesChanged(queryReplace, pkgList);
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
// Keep track of screen on/off state, but do not turn off the notification light
// until user passes through the lock screen or views the notification.
@@ -1203,9 +773,9 @@
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
// reload per-user settings
mSettingsObserver.update(null);
- updateCurrentProfilesCache(context);
+ mUserProfiles.updateCache(context);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
- updateCurrentProfilesCache(context);
+ mUserProfiles.updateCache(context);
}
}
};
@@ -1214,9 +784,6 @@
private final Uri NOTIFICATION_LIGHT_PULSE_URI
= Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
- private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
- = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
SettingsObserver(Handler handler) {
super(handler);
}
@@ -1225,8 +792,6 @@
ContentResolver resolver = getContext().getContentResolver();
resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
- false, this, UserHandle.USER_ALL);
update(null);
}
@@ -1244,9 +809,6 @@
updateNotificationPulse();
}
}
- if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) {
- rebindListenerServices();
- }
}
}
@@ -1278,7 +840,7 @@
mHandler = new WorkerHandler();
mZenModeHelper = new ZenModeHelper(getContext(), mHandler);
- mZenModeHelper.setCallback(new ZenModeHelper.Callback() {
+ mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
@Override
public void onConfigChanged() {
savePolicyFile();
@@ -1289,6 +851,9 @@
importOldBlockDb();
+ mListeners = new NotificationListeners();
+ mConditionProviders = new ConditionProviders(getContext(),
+ mHandler, mUserProfiles, mZenModeHelper);
mStatusBar = getLocalService(StatusBarManagerInternal.class);
mStatusBar.setNotificationDelegate(mNotificationDelegate);
@@ -1324,7 +889,7 @@
}
mZenModeHelper.updateZenMode();
- updateCurrentProfilesCache(getContext());
+ mUserProfiles.updateCache(getContext());
// register for various Intents
IntentFilter filter = new IntentFilter();
@@ -1403,6 +968,8 @@
// This observer will force an update when observe is called, causing us to
// bind to listener services.
mSettingsObserver.observe();
+ mListeners.onBootPhaseAppsCanStart();
+ mConditionProviders.onBootPhaseAppsCanStart();
}
}
@@ -1632,8 +1199,7 @@
public void registerListener(final INotificationListener listener,
final ComponentName component, final int userid) {
checkCallerIsSystem();
- checkNullListener(listener);
- registerListenerImpl(listener, component, userid);
+ mListeners.registerService(listener, component, userid);
}
/**
@@ -1641,10 +1207,7 @@
*/
@Override
public void unregisterListener(INotificationListener listener, int userid) {
- checkNullListener(listener);
- // no need to check permissions; if your listener binder is in the list,
- // that's proof that you had permission to add it in the first place
- unregisterListenerImpl(listener, userid);
+ mListeners.unregisterService(listener, userid);
}
/**
@@ -1661,16 +1224,16 @@
long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
- final NotificationListenerInfo info = checkListenerTokenLocked(token);
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
if (keys != null) {
final int N = keys.length;
for (int i = 0; i < N; i++) {
NotificationRecord r = mNotificationsByKey.get(keys[i]);
final int userId = r.sbn.getUserId();
if (userId != info.userid && userId != UserHandle.USER_ALL &&
- !isCurrentProfile(userId)) {
+ !mUserProfiles.isCurrentProfile(userId)) {
throw new SecurityException("Disallowed call from listener: "
- + info.listener);
+ + info.service);
}
if (r != null) {
cancelNotificationFromListenerLocked(info, callingUid, callingPid,
@@ -1688,7 +1251,7 @@
}
}
- private void cancelNotificationFromListenerLocked(NotificationListenerInfo info,
+ private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
@@ -1711,7 +1274,7 @@
long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
- final NotificationListenerInfo info = checkListenerTokenLocked(token);
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
if (info.supportsProfiles()) {
Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
+ "from " + info.component
@@ -1737,14 +1300,14 @@
public StatusBarNotification[] getActiveNotificationsFromListener(
INotificationListener token, String[] keys) {
synchronized (mNotificationList) {
- final NotificationListenerInfo info = checkListenerTokenLocked(token);
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
final ArrayList<StatusBarNotification> list
= new ArrayList<StatusBarNotification>();
if (keys == null) {
final int N = mNotificationList.size();
for (int i=0; i<N; i++) {
StatusBarNotification sbn = mNotificationList.get(i).sbn;
- if (info.enabledAndUserMatches(sbn)) {
+ if (info.enabledAndUserMatches(sbn.getUserId())) {
list.add(sbn);
}
}
@@ -1752,7 +1315,7 @@
final int N = keys.length;
for (int i=0; i<N; i++) {
NotificationRecord r = mNotificationsByKey.get(keys[i]);
- if (r != null && info.enabledAndUserMatches(r.sbn)) {
+ if (r != null && info.enabledAndUserMatches(r.sbn.getUserId())) {
list.add(r.sbn);
}
}
@@ -1779,6 +1342,37 @@
}
@Override
+ public void notifyConditions(String pkg, IConditionProvider provider,
+ Condition[] conditions) {
+ final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
+ checkCallerIsSystemOrSameApp(pkg);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mConditionProviders.notifyConditions(pkg, info, conditions);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+ enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions");
+ mConditionProviders.requestZenModeConditions(callback, requested);
+ }
+
+ @Override
+ public void setZenModeCondition(Uri conditionId) {
+ enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
+ mConditionProviders.setZenModeCondition(conditionId);
+ }
+
+ private void enforceSystemOrSystemUI(String message) {
+ if (isCallerSystem()) return;
+ getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+ message);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -1794,12 +1388,12 @@
private String[] getActiveNotificationKeysFromListener(INotificationListener token) {
synchronized (mNotificationList) {
- final NotificationListenerInfo info = checkListenerTokenLocked(token);
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
final ArrayList<String> keys = new ArrayList<String>();
final int N = mNotificationList.size();
for (int i=0; i<N; i++) {
final StatusBarNotification sbn = mNotificationList.get(i).sbn;
- if (info.enabledAndUserMatches(sbn)) {
+ if (info.enabledAndUserMatches(sbn.getUserId())) {
keys.add(sbn.getKey());
}
}
@@ -1810,19 +1404,6 @@
void dumpImpl(PrintWriter pw) {
pw.println("Current Notification Manager state:");
- pw.println(" Listeners (" + mEnabledListenersForCurrentProfiles.size()
- + ") enabled for current profiles:");
- for (ComponentName cmpt : mEnabledListenersForCurrentProfiles) {
- pw.println(" " + cmpt);
- }
-
- pw.println(" Live listeners (" + mListeners.size() + "):");
- for (NotificationListenerInfo info : mListeners) {
- pw.println(" " + info.component
- + " (user " + info.userid + "): " + info.listener
- + (info.isSystem?" SYSTEM":""));
- }
-
int N;
synchronized (mToastQueue) {
@@ -1876,6 +1457,12 @@
pw.println("\n Zen Mode:");
mZenModeHelper.dump(pw, " ");
+
+ pw.println("\n Notification listeners:");
+ mListeners.dump(pw);
+
+ pw.println("\n Condition providers:");
+ mConditionProviders.dump(pw);
}
}
@@ -2081,7 +1668,7 @@
sendAccessibilityEvent(notification, pkg);
}
- notifyPostedLocked(r);
+ mListeners.notifyPostedLocked(r.sbn);
} else {
Slog.e(TAG, "Not posting notification with icon==0: " + notification);
if (old != null && old.statusBarKey != null) {
@@ -2092,7 +1679,7 @@
Binder.restoreCallingIdentity(identity);
}
- notifyRemovedLocked(r);
+ mListeners.notifyRemovedLocked(r.sbn);
}
// ATTENTION: in a future release we will bail out here
// so that we do not play sounds, show lights, etc. for invalid
@@ -2107,7 +1694,7 @@
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (r.getUserId() == UserHandle.USER_ALL ||
(r.getUserId() == userId && r.getUserId() == currentUser) ||
- isCurrentProfile(r.getUserId()))
+ mUserProfiles.isCurrentProfile(r.getUserId()))
&& canInterrupt
&& mSystemReady
&& mAudioManager != null) {
@@ -2238,52 +1825,6 @@
idOut[0] = id;
}
- void registerListenerImpl(final INotificationListener listener,
- final ComponentName component, final int userid) {
- synchronized (mNotificationList) {
- try {
- NotificationListenerInfo info
- = new NotificationListenerInfo(listener, component, userid,
- /*isSystem*/ true, Build.VERSION_CODES.L);
- listener.asBinder().linkToDeath(info, 0);
- mListeners.add(info);
- } catch (RemoteException e) {
- // already dead
- }
- }
- }
-
- /**
- * Removes a listener from the list and unbinds from its service.
- */
- void unregisterListenerImpl(final INotificationListener listener, final int userid) {
- NotificationListenerInfo info = removeListenerImpl(listener, userid);
- if (info != null && info.connection != null) {
- getContext().unbindService(info.connection);
- }
- }
-
- /**
- * Removes a listener from the list but does not unbind from the listener's service.
- *
- * @return the removed listener.
- */
- NotificationListenerInfo removeListenerImpl(
- final INotificationListener listener, final int userid) {
- NotificationListenerInfo listenerInfo = null;
- synchronized (mNotificationList) {
- final int N = mListeners.size();
- for (int i=N-1; i>=0; i--) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (info.listener.asBinder() == listener.asBinder()
- && info.userid == userid) {
- listenerInfo = mListeners.remove(i);
- }
- }
- }
- return listenerInfo;
- }
-
void showNextToastLocked() {
ToastRecord record = mToastQueue.get(0);
while (record != null) {
@@ -2449,7 +1990,7 @@
Binder.restoreCallingIdentity(identity);
}
r.statusBarKey = null;
- notifyRemovedLocked(r);
+ mListeners.notifyRemovedLocked(r.sbn);
}
// sound
@@ -2516,7 +2057,7 @@
void cancelNotification(final int callingUid, final int callingPid,
final String pkg, final String tag, final int id,
final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
- final int userId, final int reason, final NotificationListenerInfo listener) {
+ final int userId, final int reason, final ManagedServiceInfo listener) {
// In enqueueNotificationInternal notifications are added by scheduling the
// work on the worker handler. Hence, we also schedule the cancel on this
// handler to avoid a scenario where an add notification call followed by a
@@ -2578,7 +2119,7 @@
*/
private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
return notificationMatchesUserId(r, userId)
- || isCurrentProfile(r.getUserId());
+ || mUserProfiles.isCurrentProfile(r.getUserId());
}
/**
@@ -2587,7 +2128,7 @@
*/
boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
int mustNotHaveFlags, boolean doit, int userId, int reason,
- NotificationListenerInfo listener) {
+ ManagedServiceInfo listener) {
EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
listener == null ? null : listener.component.toShortString());
@@ -2628,46 +2169,8 @@
}
}
-
-
- // Return true if the UID is a system or phone UID and therefore should not have
- // any notifications or toasts blocked.
- boolean isUidSystem(int uid) {
- final int appid = UserHandle.getAppId(uid);
- return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
- }
-
- // same as isUidSystem(int, int) for the Binder caller's UID.
- boolean isCallerSystem() {
- return isUidSystem(Binder.getCallingUid());
- }
-
- void checkCallerIsSystem() {
- if (isCallerSystem()) {
- return;
- }
- throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
- }
-
- void checkCallerIsSystemOrSameApp(String pkg) {
- if (isCallerSystem()) {
- return;
- }
- final int uid = Binder.getCallingUid();
- try {
- ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
- pkg, 0, UserHandle.getCallingUserId());
- if (!UserHandle.isSameApp(ai.uid, uid)) {
- throw new SecurityException("Calling uid " + uid + " gave package"
- + pkg + " which is owned by uid " + ai.uid);
- }
- } catch (RemoteException re) {
- throw new SecurityException("Unknown package " + pkg + "\n" + re);
- }
- }
-
void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
- NotificationListenerInfo listener, boolean includeCurrentProfiles) {
+ ManagedServiceInfo listener, boolean includeCurrentProfiles) {
EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
null, userId, 0, 0, reason,
listener == null ? null : listener.component.toShortString());
@@ -2760,34 +2263,130 @@
}
}
- private void updateCurrentProfilesCache(Context context) {
- UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if (userManager != null) {
- int currentUserId = ActivityManager.getCurrentUser();
- List<UserInfo> profiles = userManager.getProfiles(currentUserId);
- synchronized (mCurrentProfiles) {
- mCurrentProfiles.clear();
- for (UserInfo user : profiles) {
- mCurrentProfiles.put(user.id, user);
- }
+ private static boolean isUidSystem(int uid) {
+ final int appid = UserHandle.getAppId(uid);
+ return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
+ }
+
+ private static boolean isCallerSystem() {
+ return isUidSystem(Binder.getCallingUid());
+ }
+
+ private static void checkCallerIsSystem() {
+ if (isCallerSystem()) {
+ return;
+ }
+ throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
+ }
+
+ private static void checkCallerIsSystemOrSameApp(String pkg) {
+ if (isCallerSystem()) {
+ return;
+ }
+ final int uid = Binder.getCallingUid();
+ try {
+ ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+ pkg, 0, UserHandle.getCallingUserId());
+ if (!UserHandle.isSameApp(ai.uid, uid)) {
+ throw new SecurityException("Calling uid " + uid + " gave package"
+ + pkg + " which is owned by uid " + ai.uid);
}
+ } catch (RemoteException re) {
+ throw new SecurityException("Unknown package " + pkg + "\n" + re);
}
}
- private int[] getCurrentProfileIds() {
- synchronized (mCurrentProfiles) {
- int[] users = new int[mCurrentProfiles.size()];
- final int N = mCurrentProfiles.size();
- for (int i = 0; i < N; ++i) {
- users[i] = mCurrentProfiles.keyAt(i);
- }
- return users;
- }
- }
+ public class NotificationListeners extends ManagedServices {
- private boolean isCurrentProfile(int userId) {
- synchronized (mCurrentProfiles) {
- return mCurrentProfiles.get(userId) != null;
+ public NotificationListeners() {
+ super(getContext(), mHandler, mNotificationList, mUserProfiles);
+ }
+
+ @Override
+ protected Config getConfig() {
+ Config c = new Config();
+ c.caption = "notification listener";
+ c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
+ c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
+ c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
+ c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
+ c.clientLabel = R.string.notification_listener_binding_label;
+ return c;
+ }
+
+ @Override
+ protected IInterface asInterface(IBinder binder) {
+ return INotificationListener.Stub.asInterface(binder);
+ }
+
+ @Override
+ public void onServiceAdded(IInterface service) {
+ final INotificationListener listener = (INotificationListener) service;
+ final String[] keys = getActiveNotificationKeysFromListener(listener);
+ try {
+ listener.onListenerConnected(keys);
+ } catch (RemoteException e) {
+ // we tried
+ }
+ }
+
+ /**
+ * asynchronously notify all listeners about a new notification
+ */
+ public void notifyPostedLocked(StatusBarNotification sbn) {
+ // make a copy in case changes are made to the underlying Notification object
+ final StatusBarNotification sbnClone = sbn.clone();
+ for (final ManagedServiceInfo info : mServices) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ notifyPostedIfUserMatch(info, sbnClone);
+ }
+ });
+ }
+ }
+
+ /**
+ * asynchronously notify all listeners about a removed notification
+ */
+ public void notifyRemovedLocked(StatusBarNotification sbn) {
+ // make a copy in case changes are made to the underlying Notification object
+ // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
+ // notification
+ final StatusBarNotification sbnLight = sbn.cloneLight();
+ for (ManagedServiceInfo serviceInfo : mServices) {
+ final ManagedServiceInfo info = (ManagedServiceInfo) serviceInfo;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ notifyRemovedIfUserMatch(info, sbnLight);
+ }
+ });
+ }
+ }
+
+ private void notifyPostedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn) {
+ if (!info.enabledAndUserMatches(sbn.getUserId())) {
+ return;
+ }
+ final INotificationListener listener = (INotificationListener)info.service;
+ try {
+ listener.onNotificationPosted(sbn);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
+ }
+ }
+
+ private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn) {
+ if (!info.enabledAndUserMatches(sbn.getUserId())) {
+ return;
+ }
+ final INotificationListener listener = (INotificationListener)info.service;
+ try {
+ listener.onNotificationRemoved(sbn);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 80f5b5c..137730a 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -46,6 +46,7 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
@@ -69,8 +70,8 @@
private final SettingsObserver mSettingsObserver;
private final AppOpsManager mAppOps;
private final ZenModeConfig mDefaultConfig;
+ private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
- private Callback mCallback;
private int mZenMode;
private ZenModeConfig mConfig;
@@ -115,8 +116,8 @@
return new ZenModeConfig();
}
- public void setCallback(Callback callback) {
- mCallback = callback;
+ public void addCallback(Callback callback) {
+ mCallbacks.add(callback);
}
public boolean shouldIntercept(String pkg, Notification n) {
@@ -132,6 +133,14 @@
return false;
}
+ public int getZenMode() {
+ return mZenMode;
+ }
+
+ public void setZenMode(int zenModeValue) {
+ Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
+ }
+
public void updateZenMode() {
final int mode = Global.getInt(mContext.getContentResolver(),
Global.ZEN_MODE, Global.ZEN_MODE_OFF);
@@ -157,6 +166,7 @@
mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.USE_DEFAULT_STREAM_TYPE,
zen ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
exceptionPackages);
+ dispatchOnZenModeChanged();
}
public boolean allowDisable(int what, IBinder token, String pkg) {
@@ -193,7 +203,7 @@
if (config.equals(mConfig)) return true;
mConfig = config;
Slog.d(TAG, "mConfig=" + mConfig);
- if (mCallback != null) mCallback.onConfigChanged();
+ dispatchOnConfigChanged();
final String val = Integer.toString(mConfig.hashCode());
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
updateAlarms();
@@ -201,6 +211,18 @@
return true;
}
+ private void dispatchOnConfigChanged() {
+ for (Callback callback : mCallbacks) {
+ callback.onConfigChanged();
+ }
+ }
+
+ private void dispatchOnZenModeChanged() {
+ for (Callback callback : mCallbacks) {
+ callback.onZenModeChanged();
+ }
+ }
+
private boolean isCall(String pkg, Notification n) {
return CALL_PACKAGES.contains(pkg);
}
@@ -300,13 +322,14 @@
if (skip) {
Slog.d(TAG, "Skipping zen mode update for the weekend");
} else {
- Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
+ ZenModeHelper.this.setZenMode(zenModeValue);
}
updateAlarms();
}
}
- public interface Callback {
- void onConfigChanged();
+ public static class Callback {
+ void onConfigChanged() {}
+ void onZenModeChanged() {}
}
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 27c7b39..6030d4d 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -144,6 +144,7 @@
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ mainIntent.setPackage(packageName);
long ident = Binder.clearCallingIdentity();
try {
List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 702d9d2..3111cce 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -23,13 +23,13 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.system.OsConstants.S_IRWXU;
+import static android.system.OsConstants.S_IRGRP;
+import static android.system.OsConstants.S_IXGRP;
+import static android.system.OsConstants.S_IROTH;
+import static android.system.OsConstants.S_IXOTH;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
-import static libcore.io.OsConstants.S_IRWXU;
-import static libcore.io.OsConstants.S_IRGRP;
-import static libcore.io.OsConstants.S_IXGRP;
-import static libcore.io.OsConstants.S_IROTH;
-import static libcore.io.OsConstants.S_IXOTH;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
@@ -104,7 +104,6 @@
import android.os.FileObserver;
import android.os.FileUtils;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -120,6 +119,9 @@
import android.os.UserManager;
import android.security.KeyStore;
import android.security.SystemKeyStore;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.EventLog;
@@ -158,10 +160,7 @@
import java.util.Map;
import java.util.Set;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.StructStat;
import com.android.internal.R;
import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -199,8 +198,6 @@
private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
private static final int SHELL_UID = Process.SHELL_UID;
- private static final boolean GET_CERTIFICATES = true;
-
// Cap the size of permission trees that 3rd party apps can define
private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; // characters of text
@@ -278,8 +275,6 @@
final PackageHandler mHandler;
final int mSdkVersion = Build.VERSION.SDK_INT;
- final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME)
- ? null : Build.VERSION.CODENAME;
final Context mContext;
final boolean mFactoryTest;
@@ -1537,6 +1532,9 @@
mSettings.readDefaultPreferredAppsLPw(this, 0);
}
+ // All the changes are done during package scanning.
+ mSettings.updateInternalDatabaseVersion();
+
// can downgrade to reader
mSettings.writeLPr();
@@ -2165,6 +2163,24 @@
}
@Override
+ public boolean activitySupportsIntent(ComponentName component, Intent intent,
+ String resolvedType) {
+ synchronized (mPackages) {
+ PackageParser.Activity a = mActivities.mActivities.get(component);
+ if (a == null) {
+ return false;
+ }
+ for (int i=0; i<a.intents.size(); i++) {
+ if (a.intents.get(i).match(intent.getAction(), resolvedType, intent.getScheme(),
+ intent.getData(), intent.getCategories(), TAG) >= 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get receiver info");
@@ -3783,27 +3799,25 @@
private boolean collectCertificatesLI(PackageParser pp, PackageSetting ps,
PackageParser.Package pkg, File srcFile, int parseFlags) {
- if (GET_CERTIFICATES) {
- if (ps != null
- && ps.codePath.equals(srcFile)
- && ps.timeStamp == srcFile.lastModified()) {
- if (ps.signatures.mSignatures != null
- && ps.signatures.mSignatures.length != 0) {
- // Optimization: reuse the existing cached certificates
- // if the package appears to be unchanged.
- pkg.mSignatures = ps.signatures.mSignatures;
- return true;
- }
-
- Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them.");
- } else {
- Log.i(TAG, srcFile.toString() + " changed; collecting certs");
+ if (ps != null
+ && ps.codePath.equals(srcFile)
+ && ps.timeStamp == srcFile.lastModified()) {
+ if (ps.signatures.mSignatures != null
+ && ps.signatures.mSignatures.length != 0) {
+ // Optimization: reuse the existing cached certificates
+ // if the package appears to be unchanged.
+ pkg.mSignatures = ps.signatures.mSignatures;
+ return true;
}
-
- if (!pp.collectCertificates(pkg, parseFlags)) {
- mLastScanError = pp.getParseError();
- return false;
- }
+
+ Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them.");
+ } else {
+ Log.i(TAG, srcFile.toString() + " changed; collecting certs");
+ }
+
+ if (!pp.collectCertificates(pkg, parseFlags)) {
+ mLastScanError = pp.getParseError();
+ return false;
}
return true;
}
@@ -4713,7 +4727,7 @@
if (dataPath.exists()) {
int currentUid = 0;
try {
- StructStat stat = Libcore.os.stat(dataPath.getPath());
+ StructStat stat = Os.stat(dataPath.getPath());
currentUid = stat.st_uid;
} catch (ErrnoException e) {
Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
@@ -4839,7 +4853,6 @@
pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
}
}
-
pkgSetting.uidError = uidError;
}
@@ -5420,12 +5433,13 @@
}
}
- private String calculateApkRoot(final File codePath) {
+ private String calculateApkRoot(final String codePathString) {
+ final File codePath = new File(codePathString);
final File codeRoot;
if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
codeRoot = Environment.getRootDirectory();
} else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
- codeRoot = Environment.getRootDirectory();
+ codeRoot = Environment.getOemDirectory();
} else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
codeRoot = Environment.getVendorDirectory();
} else {
@@ -5457,12 +5471,12 @@
PackageSetting pkgSetting) {
// "bundled" here means system-installed with no overriding update
final boolean bundledApk = isSystemApp(pkg) && !isUpdatedSystemApp(pkg);
- final String apkName = getApkName(pkgSetting.codePathString);
+ final String apkName = getApkName(pkg.applicationInfo.sourceDir);
final File libDir;
if (bundledApk) {
// If "/system/lib64/apkname" exists, assume that is the per-package
// native library directory to use; otherwise use "/system/lib/apkname".
- String apkRoot = calculateApkRoot(pkgSetting.codePath);
+ String apkRoot = calculateApkRoot(pkg.applicationInfo.sourceDir);
File lib64 = new File(apkRoot, LIB64_DIR_NAME);
File packLib64 = new File(lib64, apkName);
libDir = (packLib64.exists()) ? lib64 : new File(apkRoot, LIB_DIR_NAME);
@@ -5484,8 +5498,7 @@
}
try {
- Libcore.os.chmod(nativeLibraryDir.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH
- | S_IXOTH);
+ Os.chmod(nativeLibraryDir.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
} catch (ErrnoException e) {
throw new IOException("Cannot chmod native library directory "
+ nativeLibraryDir.getPath(), e);
@@ -9452,7 +9465,7 @@
return;
}
}
- if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
+ if (!pp.collectCertificates(pkg, parseFlags)) {
res.returnCode = pp.getParseError();
return;
}
@@ -11063,6 +11076,8 @@
public static final int DUMP_KEYSETS = 1 << 11;
+ public static final int DUMP_VERSION = 1 << 12;
+
public static final int OPTION_SHOW_FILTERS = 1 << 0;
private int mTypes;
@@ -11161,6 +11176,7 @@
pw.println(" s[hared-users]: dump shared user IDs");
pw.println(" m[essages]: print collected runtime messages");
pw.println(" v[erifiers]: print package verifier info");
+ pw.println(" version: print database version info");
pw.println(" <package.name>: info about given package");
pw.println(" k[eysets]: print known keysets");
return;
@@ -11209,6 +11225,8 @@
dumpState.setDump(DumpState.DUMP_MESSAGES);
} else if ("v".equals(cmd) || "verifiers".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_VERIFIERS);
+ } else if ("version".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_VERSION);
} else if ("k".equals(cmd) || "keysets".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_KEYSETS);
}
@@ -11220,6 +11238,24 @@
// reader
synchronized (mPackages) {
+ if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
+ if (!checkin) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Database versions:");
+ pw.print(" SDK Version:");
+ pw.print(" internal=");
+ pw.print(mSettings.mInternalSdkPlatform);
+ pw.print(" external=");
+ pw.println(mSettings.mExternalSdkPlatform);
+ pw.print(" DB Version:");
+ pw.print(" internal=");
+ pw.print(mSettings.mInternalDatabaseVersion);
+ pw.print(" external=");
+ pw.println(mSettings.mExternalDatabaseVersion);
+ }
+ }
+
if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
if (!checkin) {
if (dumpState.onTitlePrinted())
@@ -11750,6 +11786,9 @@
| (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
+
+ mSettings.updateExternalDatabaseVersion();
+
// can downgrade to reader
// Persist settings
mSettings.writeLPr();
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 80f716c..a69940f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -89,6 +89,28 @@
final class Settings {
private static final String TAG = "PackageSettings";
+ /**
+ * Current version of the package database. Set it to the latest version in
+ * the {@link DatabaseVersion} class below to ensure the database upgrade
+ * doesn't happen repeatedly.
+ * <p>
+ * Note that care should be taken to make sure all database upgrades are
+ * idempotent.
+ */
+ private static final int CURRENT_DATABASE_VERSION = DatabaseVersion.FIRST_VERSION;
+
+ /**
+ * This class contains constants that can be referred to from upgrade code.
+ * Insert constant values here that describe the upgrade reason. The version
+ * code must be monotonically increasing.
+ */
+ public static class DatabaseVersion {
+ /**
+ * The initial version of the database.
+ */
+ public static final int FIRST_VERSION = 1;
+ }
+
private static final boolean DEBUG_STOPPED = false;
private static final boolean DEBUG_MU = false;
@@ -133,6 +155,14 @@
int mInternalSdkPlatform;
int mExternalSdkPlatform;
+ /**
+ * The current database version for apps on internal storage. This is
+ * used to upgrade the format of the packages.xml database not necessarily
+ * tied to an SDK version.
+ */
+ int mInternalDatabaseVersion;
+ int mExternalDatabaseVersion;
+
Boolean mReadExternalStorageEnforced;
/** Device identity for the purpose of package verification. */
@@ -825,6 +855,40 @@
}
}
+ /**
+ * Returns whether the current database has is older than {@code version}
+ * for apps on internal storage.
+ */
+ public boolean isInternalDatabaseVersionOlderThan(int version) {
+ return mInternalDatabaseVersion < version;
+ }
+
+ /**
+ * Returns whether the current database has is older than {@code version}
+ * for apps on external storage.
+ */
+ public boolean isExternalDatabaseVersionOlderThan(int version) {
+ return mExternalDatabaseVersion < version;
+ }
+
+ /**
+ * Updates the database version for apps on internal storage. Called after
+ * call the updates to the database format are done for apps on internal
+ * storage after the initial start-up scan.
+ */
+ public void updateInternalDatabaseVersion() {
+ mInternalDatabaseVersion = CURRENT_DATABASE_VERSION;
+ }
+
+ /**
+ * Updates the database version for apps on internal storage. Called after
+ * call the updates to the database format are done for apps on internal
+ * storage after the initial start-up scan.
+ */
+ public void updateExternalDatabaseVersion() {
+ mExternalDatabaseVersion = CURRENT_DATABASE_VERSION;
+ }
+
private void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
@@ -1355,6 +1419,11 @@
serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
serializer.endTag(null, "last-platform-version");
+ serializer.startTag(null, "database-version");
+ serializer.attribute(null, "internal", Integer.toString(mInternalDatabaseVersion));
+ serializer.attribute(null, "external", Integer.toString(mExternalDatabaseVersion));
+ serializer.endTag(null, "database-version");
+
if (mVerifierDeviceIdentity != null) {
serializer.startTag(null, "verifier");
serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
@@ -1830,6 +1899,19 @@
}
} catch (NumberFormatException e) {
}
+ } else if (tagName.equals("database-version")) {
+ mInternalDatabaseVersion = mExternalDatabaseVersion = 0;
+ try {
+ String internalDbVersionString = parser.getAttributeValue(null, "internal");
+ if (internalDbVersionString != null) {
+ mInternalDatabaseVersion = Integer.parseInt(internalDbVersionString);
+ }
+ String externalDbVersionString = parser.getAttributeValue(null, "external");
+ if (externalDbVersionString != null) {
+ mExternalDatabaseVersion = Integer.parseInt(externalDbVersionString);
+ }
+ } catch (NumberFormatException ignored) {
+ }
} else if (tagName.equals("verifier")) {
final String deviceIdentity = parser.getAttributeValue(null, "device");
try {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 53db9ef..f8103de 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -22,8 +22,8 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
-import android.app.admin.DevicePolicyManager;
import android.app.IStopUserCallback;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -258,24 +258,62 @@
}
@Override
- public List<UserInfo> getProfiles(int userId) {
+ public List<UserInfo> getProfiles(int userId, boolean enabledOnly) {
if (userId != UserHandle.getCallingUserId()) {
checkManageUsersPermission("getting profiles related to user " + userId);
}
- synchronized (mPackagesLock) {
- UserInfo user = getUserInfoLocked(userId);
- ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
- for (int i = 0; i < mUsers.size(); i++) {
- UserInfo profile = mUsers.valueAt(i);
- if (!isProfileOf(user, profile)) {
- continue;
- }
- users.add(profile);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mPackagesLock) {
+ return getProfilesLocked(userId, enabledOnly);
}
- return users;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
+ /** Assume permissions already checked and caller's identity cleared */
+ private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) {
+ // Getting the service here is not good for testing purposes.
+ // However, this service is not available when UserManagerService starts
+ // up so we need a lazy load.
+
+ DevicePolicyManager dpm = null;
+ if (enabledOnly) {
+ dpm = (DevicePolicyManager)
+ mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ }
+
+ UserInfo user = getUserInfoLocked(userId);
+ ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserInfo profile = mUsers.valueAt(i);
+ if (!isProfileOf(user, profile)) {
+ continue;
+ }
+
+ if (enabledOnly && profile.isManagedProfile()) {
+ if (dpm != null) {
+ if (!dpm.isProfileEnabled(profile.id)) {
+ continue;
+ }
+ } else {
+ Log.w(LOG_TAG,
+ "Attempting to reach DevicePolicyManager before it is started");
+ // TODO: There might be system apps that need to call this.
+ // Make sure that DevicePolicyManagerService is ready at that
+ // time (otherwise, any default value is a bad one).
+ throw new IllegalArgumentException(String.format(
+ "Attempting to get enabled profiles for %d before "
+ + "DevicePolicyManagerService has been started.",
+ userId));
+ }
+ }
+ users.add(profile);
+ }
+ return users;
+ }
+
private boolean isProfileOf(UserInfo user, UserInfo profile) {
return user.id == profile.id ||
(user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
@@ -432,13 +470,13 @@
synchronized (mPackagesLock) {
Bundle restrictions = mUserRestrictions.get(userId);
- return restrictions != null ? restrictions : Bundle.EMPTY;
+ return restrictions != null ? new Bundle(restrictions) : new Bundle();
}
}
@Override
public void setUserRestrictions(Bundle restrictions, int userId) {
- checkProfileOwnerOrManageUsersPermission("setUserRestrictions");
+ checkManageUsersPermission("setUserRestrictions");
if (restrictions == null) return;
synchronized (mPackagesLock) {
@@ -464,51 +502,14 @@
* @param message used as message if SecurityException is thrown
* @throws SecurityException if the caller is not system or root
*/
- private final void checkManageUsersPermission(String message) {
+ private static final void checkManageUsersPermission(String message) {
final int uid = Binder.getCallingUid();
-
- if (missingManageUsersPermission(uid)) {
- throw new SecurityException("You need MANAGE_USERS permission to: " + message);
- }
- }
-
- /**
- * Enforces that only the system UID, root's UID, apps that have the
- * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
- * permission, the profile owner, or the device owner can make certain calls to the
- * UserManager.
- *
- * @param message used as message if SecurityException is thrown
- * @throws SecurityException if the caller is not system, root, or device
- * owner
- */
- private final void checkProfileOwnerOrManageUsersPermission(String message) {
- final int uid = Binder.getCallingUid();
- boolean isProfileOwner = false;
- if (mContext != null && mContext.getPackageManager() != null) {
- String[] pkgs = mContext.getPackageManager().getPackagesForUid(uid);
- DevicePolicyManager dpm =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- if (dpm != null) {
- for (String pkg : pkgs) {
- if (dpm.isDeviceOwnerApp(pkg) || dpm.isProfileOwnerApp(pkg)) {
- isProfileOwner = true;
- }
- }
- }
- }
-
- if (missingManageUsersPermission(uid) && !isProfileOwner) {
- throw new SecurityException(
- "You need MANAGE_USERS permission or device owner privileges to: " + message);
- }
- }
-
- private boolean missingManageUsersPermission(int uid) {
- return uid != Process.SYSTEM_UID && uid != 0
+ if (uid != Process.SYSTEM_UID && uid != 0
&& ActivityManager.checkComponentPermission(
android.Manifest.permission.MANAGE_USERS,
- uid, -1, true) != PackageManager.PERMISSION_GRANTED;
+ uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("You need MANAGE_USERS permission to: " + message);
+ }
}
private void writeBitmapLocked(UserInfo info, Bitmap bitmap) {
@@ -1213,8 +1214,7 @@
public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
if (UserHandle.getCallingUserId() != userId
|| !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
- checkProfileOwnerOrManageUsersPermission(
- "Only system or device owner can get restrictions for other users/apps");
+ checkManageUsersPermission("Only system can get restrictions for other users/apps");
}
synchronized (mPackagesLock) {
// Read the restrictions from XML
@@ -1227,8 +1227,7 @@
int userId) {
if (UserHandle.getCallingUserId() != userId
|| !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
- checkProfileOwnerOrManageUsersPermission(
- "Only system or device owner can set restrictions for other users/apps");
+ checkManageUsersPermission("Only system can set restrictions for other users/apps");
}
synchronized (mPackagesLock) {
// Write the restrictions to XML
@@ -1330,8 +1329,7 @@
@Override
public void removeRestrictions() {
- checkProfileOwnerOrManageUsersPermission(
- "Only system or device owner can remove restrictions");
+ checkManageUsersPermission("Only system can remove restrictions");
final int userHandle = UserHandle.getCallingUserId();
removeRestrictionsForUser(userHandle, true);
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 6700895..649f9dc 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -19,6 +19,9 @@
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -26,13 +29,18 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.database.Cursor;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.TvContract;
import android.tv.ITvInputClient;
import android.tv.ITvInputManager;
import android.tv.ITvInputService;
@@ -41,13 +49,14 @@
import android.tv.ITvInputSessionCallback;
import android.tv.TvInputInfo;
import android.tv.TvInputService;
-import android.util.ArrayMap;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.InputChannel;
import android.view.Surface;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.SomeArgs;
+import com.android.server.IoThread;
import com.android.server.SystemService;
import java.util.ArrayList;
@@ -63,6 +72,8 @@
private final Context mContext;
+ private final ContentResolver mContentResolver;
+
// A global lock.
private final Object mLock = new Object();
@@ -72,10 +83,17 @@
// A map from user id to UserState.
private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
+ private final Handler mLogHandler;
+
public TvInputManagerService(Context context) {
super(context);
+
mContext = context;
+ mContentResolver = context.getContentResolver();
+ mLogHandler = new LogHandler(IoThread.get().getLooper());
+
registerBroadcastReceivers();
+
synchronized (mLock) {
mUserStates.put(mCurrentUserId, new UserState());
buildTvInputListLocked(mCurrentUserId);
@@ -274,6 +292,9 @@
Slog.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName()
+ ")");
}
+
+ final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
+
// Set up a callback to send the session token.
ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
@Override
@@ -286,30 +307,32 @@
if (session == null) {
removeSessionStateLocked(sessionToken, userId);
sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
- sessionState.seq, userId);
+ null, sessionState.seq, userId);
} else {
sendSessionTokenToClientLocked(sessionState.client, sessionState.name,
- sessionToken, sessionState.seq, userId);
+ sessionToken, channels[0], sessionState.seq, userId);
}
+ channels[0].dispose();
}
}
};
// Create a session. When failed, send a null token immediately.
try {
- service.createSession(callback);
+ service.createSession(channels[1], callback);
} catch (RemoteException e) {
Slog.e(TAG, "error in createSession", e);
removeSessionStateLocked(sessionToken, userId);
- sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
+ sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null, null,
sessionState.seq, userId);
}
+ channels[1].dispose();
}
private void sendSessionTokenToClientLocked(ITvInputClient client, ComponentName name,
- IBinder sessionToken, int seq, int userId) {
+ IBinder sessionToken, InputChannel channel, int seq, int userId) {
try {
- client.onSessionCreated(name, sessionToken, seq);
+ client.onSessionCreated(name, sessionToken, channel, seq);
} catch (RemoteException exception) {
Slog.e(TAG, "error in onSessionCreated", exception);
}
@@ -325,6 +348,14 @@
UserState userState = getUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
+ // Close the open log entry, if any.
+ if (sessionState.logUri != null) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = sessionState.logUri;
+ args.arg2 = System.currentTimeMillis();
+ mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget();
+ }
+
// Also remove the session token from the session token list of the current service.
ServiceState serviceState = userState.serviceStateMap.get(sessionState.name);
if (serviceState != null) {
@@ -384,7 +415,7 @@
UserState userState = getUserStateLocked(resolvedUserId);
ServiceState serviceState = userState.serviceStateMap.get(name);
if (serviceState == null) {
- serviceState = new ServiceState(name, resolvedUserId);
+ serviceState = new ServiceState(resolvedUserId);
userState.serviceStateMap.put(name, serviceState);
}
IBinder iBinder = client.asBinder();
@@ -468,7 +499,7 @@
// Also, add them to the session state map of the current service.
ServiceState serviceState = userState.serviceStateMap.get(name);
if (serviceState == null) {
- serviceState = new ServiceState(name, resolvedUserId);
+ serviceState = new ServiceState(resolvedUserId);
userState.serviceStateMap.put(name, serviceState);
}
serviceState.sessionTokens.add(sessionToken);
@@ -557,6 +588,35 @@
synchronized (mLock) {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri);
+
+ long currentTime = System.currentTimeMillis();
+ long channelId = ContentUris.parseId(channelUri);
+
+ // Close the open log entry first, if any.
+ UserState userState = getUserStateLocked(resolvedUserId);
+ SessionState sessionState = userState.sessionStateMap.get(sessionToken);
+ if (sessionState.logUri != null) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = sessionState.logUri;
+ args.arg2 = currentTime;
+ mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args)
+ .sendToTarget();
+ }
+
+ // Create a log entry and fill it later.
+ ContentValues values = new ContentValues();
+ values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+ currentTime);
+ values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, 0);
+ values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
+
+ sessionState.logUri = mContentResolver.insert(
+ TvContract.WatchedPrograms.CONTENT_URI, values);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = sessionState.logUri;
+ args.arg2 = ContentUris.parseId(channelUri);
+ args.arg3 = currentTime;
+ mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
} catch (RemoteException e) {
Slog.e(TAG, "error in tune", e);
return;
@@ -652,7 +712,7 @@
private boolean bound;
private boolean available;
- private ServiceState(ComponentName name, int userId) {
+ private ServiceState(int userId) {
this.connection = new InputServiceConnection(userId);
}
}
@@ -664,6 +724,7 @@
private final int callingUid;
private ITvInputSession session;
+ private Uri logUri;
private SessionState(ComponentName name, ITvInputClient client, int seq, int callingUid) {
this.name = name;
@@ -738,4 +799,147 @@
}
}
}
+
+ private final class LogHandler extends Handler {
+ private static final int MSG_OPEN_ENTRY = 1;
+ private static final int MSG_UPDATE_ENTRY = 2;
+ private static final int MSG_CLOSE_ENTRY = 3;
+
+ public LogHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_OPEN_ENTRY: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Uri uri = (Uri) args.arg1;
+ long channelId = (long) args.arg2;
+ long time = (long) args.arg3;
+ onOpenEntry(uri, channelId, time);
+ args.recycle();
+ return;
+ }
+ case MSG_UPDATE_ENTRY: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Uri uri = (Uri) args.arg1;
+ long channelId = (long) args.arg2;
+ long time = (long) args.arg3;
+ onUpdateEntry(uri, channelId, time);
+ args.recycle();
+ return;
+ }
+ case MSG_CLOSE_ENTRY: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Uri uri = (Uri) args.arg1;
+ long time = (long) args.arg2;
+ onCloseEntry(uri, time);
+ args.recycle();
+ return;
+ }
+ default: {
+ Slog.w(TAG, "Unhandled message code: " + msg.what);
+ return;
+ }
+ }
+ }
+
+ private void onOpenEntry(Uri uri, long channelId, long watchStarttime) {
+ String[] projection = {
+ TvContract.Programs.TITLE,
+ TvContract.Programs.START_TIME_UTC_MILLIS,
+ TvContract.Programs.END_TIME_UTC_MILLIS,
+ TvContract.Programs.DESCRIPTION
+ };
+ String selection = TvContract.Programs.CHANNEL_ID + "=? AND "
+ + TvContract.Programs.START_TIME_UTC_MILLIS + "<=? AND "
+ + TvContract.Programs.END_TIME_UTC_MILLIS + ">?";
+ String[] selectionArgs = {
+ String.valueOf(channelId),
+ String.valueOf(watchStarttime),
+ String.valueOf(watchStarttime)
+ };
+ String sortOrder = TvContract.Programs.START_TIME_UTC_MILLIS + " ASC";
+ Cursor cursor = null;
+ try {
+ cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection,
+ selection, selectionArgs, sortOrder);
+ if (cursor != null && cursor.moveToNext()) {
+ ContentValues values = new ContentValues();
+ values.put(TvContract.WatchedPrograms.TITLE, cursor.getString(0));
+ values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, cursor.getLong(1));
+ long endTime = cursor.getLong(2);
+ values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime);
+ values.put(TvContract.WatchedPrograms.DESCRIPTION, cursor.getString(3));
+ mContentResolver.update(uri, values, null, null);
+
+ // Schedule an update when the current program ends.
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = uri;
+ args.arg2 = channelId;
+ args.arg3 = endTime;
+ Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args);
+ sendMessageDelayed(msg, endTime - System.currentTimeMillis());
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ private void onUpdateEntry(Uri uri, long channelId, long time) {
+ String[] projection = {
+ TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.TITLE,
+ TvContract.WatchedPrograms.START_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.END_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.DESCRIPTION
+ };
+ Cursor cursor = null;
+ try {
+ cursor = mContentResolver.query(uri, projection, null, null, null);
+ if (cursor != null && cursor.moveToNext()) {
+ long watchStartTime = cursor.getLong(0);
+ long watchEndTime = cursor.getLong(1);
+ String title = cursor.getString(2);
+ long startTime = cursor.getLong(3);
+ long endTime = cursor.getLong(4);
+ String description = cursor.getString(5);
+
+ // Do nothing if the current log entry is already closed.
+ if (watchEndTime > 0) {
+ return;
+ }
+
+ // The current program has just ended. Create a (complete) log entry off the
+ // current entry.
+ ContentValues values = new ContentValues();
+ values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+ watchStartTime);
+ values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, time);
+ values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
+ values.put(TvContract.WatchedPrograms.TITLE, title);
+ values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, startTime);
+ values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime);
+ values.put(TvContract.WatchedPrograms.DESCRIPTION, description);
+ mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ // Re-open the current log entry with the next program information.
+ onOpenEntry(uri, channelId, time);
+ }
+
+ private void onCloseEntry(Uri uri, long watchEndTime) {
+ ContentValues values = new ContentValues();
+ values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, watchEndTime);
+ mContentResolver.update(uri, values, null, null);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
index fdc604f..3c960c7 100644
--- a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -20,6 +20,8 @@
import android.content.Intent;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Base64;
import android.util.Slog;
@@ -28,9 +30,7 @@
import java.io.FileInputStream;
import java.io.IOException;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver {
@@ -110,16 +110,16 @@
File update = new File(updateDir.getParentFile(), "update");
File tmp = new File(updateDir.getParentFile(), "tmp");
if (current.exists()) {
- Libcore.os.symlink(updateDir.getPath(), update.getPath());
- Libcore.os.rename(update.getPath(), current.getPath());
+ Os.symlink(updateDir.getPath(), update.getPath());
+ Os.rename(update.getPath(), current.getPath());
} else {
- Libcore.os.symlink(updateDir.getPath(), current.getPath());
+ Os.symlink(updateDir.getPath(), current.getPath());
}
contexts.mkdirs();
backupContexts(contexts);
copyUpdate(contexts);
- Libcore.os.symlink(contexts.getPath(), tmp.getPath());
- Libcore.os.rename(tmp.getPath(), current.getPath());
+ Os.symlink(contexts.getPath(), tmp.getPath());
+ Os.rename(tmp.getPath(), current.getPath());
SystemProperties.set("selinux.reload_policy", "1");
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 87953fe..3eb2d5f 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -25,6 +25,7 @@
import android.app.IWallpaperManagerCallback;
import android.app.PendingIntent;
import android.app.WallpaperInfo;
+import android.app.WallpaperManager;
import android.app.backup.BackupManager;
import android.app.backup.WallpaperBackupHelper;
import android.content.BroadcastReceiver;
@@ -844,13 +845,7 @@
try {
if (componentName == null) {
- String defaultComponent =
- mContext.getString(com.android.internal.R.string.default_wallpaper_component);
- if (defaultComponent != null) {
- // See if there is a default wallpaper component specified
- componentName = ComponentName.unflattenFromString(defaultComponent);
- if (DEBUG) Slog.v(TAG, "Use default component wallpaper:" + componentName);
- }
+ componentName = WallpaperManager.getDefaultWallpaperComponent(mContext);
if (componentName == null) {
// Fall back to static image wallpaper
componentName = IMAGE_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index f17b2f4..9039236 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -162,13 +162,10 @@
private final Interpolator mThumbnailFadeoutInterpolator;
private int mCurrentUserId = 0;
- private boolean mUseAlternateThumbnailAnimation;
AppTransition(Context context, Handler h) {
mContext = context;
mH = h;
- mUseAlternateThumbnailAnimation =
- SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
mConfigShortAnimTime = context.getResources().getInteger(
com.android.internal.R.integer.config_shortAnimTime);
mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
@@ -668,7 +665,7 @@
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
int appWidth, int appHeight, int orientation,
- Rect containingFrame, Rect contentInsets) {
+ Rect containingFrame, Rect contentInsets, Configuration configuration) {
Animation a;
if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -689,7 +686,8 @@
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
- if (mUseAlternateThumbnailAnimation) {
+ boolean useAlternateThumbnailAnimation = (configuration.smallestScreenWidthDp < 600);
+ if (useAlternateThumbnailAnimation) {
a = createAlternateThumbnailEnterExitAnimationLocked(
getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
transit, containingFrame, contentInsets);
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
index fbfca93..35d19c1 100644
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -22,7 +22,6 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
@@ -40,6 +39,7 @@
private int mLastDH;
private boolean mDrawNeeded;
private Paint mPaint;
+ private int mRotation;
public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) {
SurfaceControl ctrl = null;
@@ -78,7 +78,26 @@
if (c == null) {
return;
}
- c.drawCircle(160, 160, 160, mPaint);
+ int cx = 160;
+ int cy = 160;
+ switch (mRotation) {
+ case Surface.ROTATION_0:
+ case Surface.ROTATION_90:
+ // chin bottom or right
+ cx = 160;
+ cy = 160;
+ break;
+ case Surface.ROTATION_180:
+ // chin top
+ cx = 160;
+ cy = 145;
+ break;
+ case Surface.ROTATION_270:
+ cx = 145;
+ cy = 160;
+ break;
+ }
+ c.drawCircle(cx, cy, 160, mPaint);
mSurface.unlockCanvasAndPost(c);
}
@@ -97,7 +116,7 @@
}
}
- void positionSurface(int dw, int dh) {
+ void positionSurface(int dw, int dh, int rotation) {
if (mLastDW == dw && mLastDH == dh) {
return;
}
@@ -105,6 +124,7 @@
mLastDH = dh;
mSurfaceControl.setSize(dw, dh);
mDrawNeeded = true;
+ mRotation = rotation;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 524d78b..637beec 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -287,8 +287,6 @@
private static final String DENSITY_OVERRIDE = "ro.config.density_override";
private static final String SIZE_OVERRIDE = "ro.config.size_override";
- private static final String SCREEN_CIRCULAR = "ro.display.circular";
-
private static final int MAX_SCREENSHOT_RETRIES = 3;
final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -3192,7 +3190,7 @@
}
Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
- mCurConfiguration.orientation, containingFrame, contentInsets);
+ mCurConfiguration.orientation, containingFrame, contentInsets, mCurConfiguration);
if (a != null) {
if (DEBUG_ANIM) {
RuntimeException e = null;
@@ -5489,7 +5487,9 @@
}
public void showCircularDisplayMaskIfNeeded() {
- if (SystemProperties.getBoolean(SCREEN_CIRCULAR, false)) {
+ // we're fullscreen and not hosted in an ActivityView
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_windowIsRound)) {
mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK));
}
}
@@ -8660,8 +8660,7 @@
wtoken.deferClearAllDrawn = false;
}
- boolean useAlternateThumbnailAnimation =
- SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
+ boolean useAlternateThumbnailAnimation = (mCurConfiguration.smallestScreenWidthDp < 600);
AppWindowAnimator appAnimator =
topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
@@ -9001,7 +9000,7 @@
mStrictModeFlash.positionSurface(defaultDw, defaultDh);
}
if (mCircularDisplayMask != null) {
- mCircularDisplayMask.positionSurface(defaultDw, defaultDh);
+ mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation);
}
boolean focusDisplayed = false;
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 1b3887c..51583a5 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -11,7 +11,9 @@
$(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_HdmiCecService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
new file mode 100644
index 0000000..f3e8f3c
--- /dev/null
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 "HdmiCecControllerJni"
+
+#define LOG_NDEBUG 1
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <hardware/hdmi_cec.h>
+
+namespace android {
+
+static struct {
+ jmethodID handleMessage;
+} gHdmiCecControllerClassInfo;
+
+
+class HdmiCecController {
+public:
+ HdmiCecController(jobject callbacksObj);
+
+private:
+ static void onReceived(const hdmi_event_t* event, void* arg);
+
+ jobject mCallbacksObj;
+};
+
+HdmiCecController::HdmiCecController(jobject callbacksObj) :
+ mCallbacksObj(callbacksObj) {
+}
+
+// static
+void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
+ HdmiCecController* handler = static_cast<HdmiCecController*>(arg);
+ if (handler == NULL) {
+ return;
+ }
+
+ // TODO: propagate message to Java layer.
+}
+
+
+//------------------------------------------------------------------------------
+static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) {
+ // TODO: initialize hal and pass it to controller if ready.
+
+ HdmiCecController* controller = new HdmiCecController(
+ env->NewGlobalRef(callbacksObj));
+
+ return reinterpret_cast<jlong>(controller);
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J",
+ (void *) nativeInit },
+};
+
+#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
+
+int register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bf9f7f4..1feb325 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -38,7 +38,9 @@
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_HdmiCecService(JNIEnv* env);
+int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
};
using namespace android;
@@ -72,7 +74,10 @@
register_android_server_ConsumerIrService(env);
register_android_server_dreams_McuHal(env);
register_android_server_BatteryStatsService(env);
+ register_android_server_hdmi_HdmiCecController(env);
+ // TODO: remove this once replaces HdmiCecService with HdmiControlService.
register_android_server_hdmi_HdmiCecService(env);
+ register_android_server_hdmi_HdmiMhlController(env);
return JNI_VERSION_1_4;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 1b048a1..3c46e40 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -53,6 +53,7 @@
private static final String ATTR_NAME = "name";
private static final String ATTR_PACKAGE = "package";
private static final String ATTR_USERID = "userId";
+ private static final String ATTR_ENABLED = "profileEnabled";
private AtomicFile fileForWriting;
@@ -61,11 +62,10 @@
private OutputStream mOutputStreamForTest;
// Internal state for the device owner package.
- private String mDeviceOwnerPackageName;
- private String mDeviceOwnerName;
+ private OwnerInfo mDeviceOwner;
// Internal state for the profile owner packages.
- private final HashMap<Integer, String[]> mProfileOwners = new HashMap<Integer, String[]>();
+ private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
// Private default constructor.
private DeviceOwner() {
@@ -95,8 +95,7 @@
*/
static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
DeviceOwner owner = new DeviceOwner();
- owner.mDeviceOwnerPackageName = packageName;
- owner.mDeviceOwnerName = ownerName;
+ owner.mDeviceOwner = new OwnerInfo(ownerName, packageName);
return owner;
}
@@ -105,25 +104,25 @@
*/
static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
DeviceOwner owner = new DeviceOwner();
- owner.mProfileOwners.put(userId, new String[] { packageName, ownerName });
+ owner.mProfileOwners.put(
+ userId, new OwnerInfo(ownerName, packageName, false /* disabled */));
return owner;
}
String getDeviceOwnerPackageName() {
- return mDeviceOwnerPackageName;
+ return mDeviceOwner != null ? mDeviceOwner.packageName : null;
}
String getDeviceOwnerName() {
- return mDeviceOwnerName;
+ return mDeviceOwner != null ? mDeviceOwner.name : null;
}
void setDeviceOwner(String packageName, String ownerName) {
- mDeviceOwnerPackageName = packageName;
- mDeviceOwnerName = ownerName;
+ mDeviceOwner = new OwnerInfo(ownerName, packageName);
}
void setProfileOwner(String packageName, String ownerName, int userId) {
- mProfileOwners.put(userId, new String[] { packageName, ownerName });
+ mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName, false /* disabled */));
}
void removeProfileOwner(int userId) {
@@ -131,17 +130,30 @@
}
String getProfileOwnerPackageName(int userId) {
- String[] profileOwner = mProfileOwners.get(userId);
- return profileOwner != null ? profileOwner[0] : null;
+ OwnerInfo profileOwner = mProfileOwners.get(userId);
+ return profileOwner != null ? profileOwner.packageName : null;
}
String getProfileOwnerName(int userId) {
- String[] profileOwner = mProfileOwners.get(userId);
- return profileOwner != null ? profileOwner[1] : null;
+ OwnerInfo profileOwner = mProfileOwners.get(userId);
+ return profileOwner != null ? profileOwner.name : null;
+ }
+
+ boolean isProfileEnabled(int userId) {
+ OwnerInfo profileOwner = mProfileOwners.get(userId);
+ return profileOwner != null ? profileOwner.enabled : true;
+ }
+
+ void setProfileEnabled(int userId) {
+ OwnerInfo profileOwner = mProfileOwners.get(userId);
+ if (profileOwner == null) {
+ throw new IllegalArgumentException("No profile owner exists.");
+ }
+ profileOwner.enabled = true;
}
boolean hasDeviceOwner() {
- return mDeviceOwnerPackageName != null;
+ return mDeviceOwner != null;
}
static boolean isInstalled(String packageName, PackageManager pm) {
@@ -185,14 +197,18 @@
String tag = parser.getName();
if (tag.equals(TAG_DEVICE_OWNER)) {
- mDeviceOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
- mDeviceOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+ mDeviceOwner = new OwnerInfo(
+ parser.getAttributeValue(null, ATTR_NAME),
+ parser.getAttributeValue(null, ATTR_PACKAGE));
} else if (tag.equals(TAG_PROFILE_OWNER)) {
String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+ Boolean profileEnabled = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_ENABLED));
int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
mProfileOwners.put(userId,
- new String[] { profileOwnerPackageName, profileOwnerName });
+ new OwnerInfo(
+ profileOwnerName, profileOwnerPackageName, profileEnabled));
} else {
throw new XmlPullParserException(
"Unexpected tag in device owner file: " + tag);
@@ -220,21 +236,22 @@
out.startDocument(null, true);
// Write device owner tag
- if (mDeviceOwnerPackageName != null) {
+ if (mDeviceOwner != null) {
out.startTag(null, TAG_DEVICE_OWNER);
- out.attribute(null, ATTR_PACKAGE, mDeviceOwnerPackageName);
- if (mDeviceOwnerName != null) {
- out.attribute(null, ATTR_NAME, mDeviceOwnerName);
+ out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
+ if (mDeviceOwner.packageName != null) {
+ out.attribute(null, ATTR_NAME, mDeviceOwner.packageName);
}
out.endTag(null, TAG_DEVICE_OWNER);
}
// Write profile owner tags
if (mProfileOwners.size() > 0) {
- for (HashMap.Entry<Integer, String[]> owner : mProfileOwners.entrySet()) {
+ for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
out.startTag(null, TAG_PROFILE_OWNER);
- out.attribute(null, ATTR_PACKAGE, owner.getValue()[0]);
- out.attribute(null, ATTR_NAME, owner.getValue()[1]);
+ out.attribute(null, ATTR_PACKAGE, owner.getValue().packageName);
+ out.attribute(null, ATTR_NAME, owner.getValue().name);
+ out.attribute(null, ATTR_ENABLED, String.valueOf(owner.getValue().enabled));
out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
out.endTag(null, TAG_PROFILE_OWNER);
}
@@ -271,4 +288,20 @@
fileForWriting.finishWrite((FileOutputStream) stream);
}
}
-}
\ No newline at end of file
+
+ static class OwnerInfo {
+ public String name;
+ public String packageName;
+ public boolean enabled = true; // only makes sense for managed profiles
+
+ public OwnerInfo(String name, String packageName, boolean enabled) {
+ this(name, packageName);
+ this.enabled = enabled;
+ }
+
+ public OwnerInfo(String name, String packageName) {
+ this.name = name;
+ this.packageName = packageName;
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d6f9dea..f1ee280 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2828,7 +2828,7 @@
return null;
}
synchronized (this) {
- if (mDeviceOwner != null) {
+ if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
return mDeviceOwner.getDeviceOwnerPackageName();
}
}
@@ -2900,9 +2900,13 @@
}
// Check if this is the profile owner who is calling
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- Slog.d(LOG_TAG, "Enabling the profile for: " + UserHandle.getCallingUserId());
- long id = Binder.clearCallingIdentity();
+ int userId = UserHandle.getCallingUserId();
+ Slog.d(LOG_TAG, "Enabling the profile for: " + userId);
+ mDeviceOwner.setProfileEnabled(userId);
+ mDeviceOwner.writeOwnerFile();
+
+ long id = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId()));
@@ -2944,6 +2948,23 @@
return null;
}
+ @Override
+ public boolean isProfileEnabled(int userHandle) {
+ if (!mHasFeature) {
+ // If device policy management is not enabled, then the userHandle cannot belong to a
+ // managed profile. All other profiles are considered enabled.
+ return true;
+ }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+
+ synchronized (this) {
+ if (mDeviceOwner != null) {
+ return mDeviceOwner.isProfileEnabled(userHandle);
+ }
+ }
+ return true;
+ }
+
private boolean isDeviceProvisioned() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) > 0;
@@ -3097,4 +3118,24 @@
}
}
}
+
+ @Override
+ public void setUserRestriction(ComponentName who, String key, boolean enabled) {
+ final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
+
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ UserManager um = UserManager.get(mContext);
+ long id = Binder.clearCallingIdentity();
+ try {
+ um.setUserRestriction(key, enabled, userHandle);
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f08d69f..3d82027 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -29,6 +29,7 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.AudioService;
+import android.os.Build;
import android.os.Environment;
import android.os.FactoryTest;
import android.os.Handler;
@@ -59,8 +60,10 @@
import com.android.server.am.BatteryStatsService;
import com.android.server.clipboard.ClipboardService;
import com.android.server.content.ContentService;
+import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
+import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LightsService;
@@ -110,10 +113,10 @@
*/
private static final String BACKUP_MANAGER_SERVICE_CLASS =
"com.android.server.backup.BackupManagerService$Lifecycle";
- private static final String DEVICE_POLICY_MANAGER_SERVICE_CLASS =
- "com.android.server.devicepolicy.DevicePolicyManagerService$Lifecycle";
private static final String APPWIDGET_SERVICE_CLASS =
"com.android.server.appwidget.AppWidgetService";
+ private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS =
+ "com.android.server.voiceinteraction.VoiceInteractionManagerService";
private static final String PRINT_MANAGER_SERVICE_CLASS =
"com.android.server.print.PrintManagerService";
private static final String USB_SERVICE_CLASS =
@@ -198,6 +201,10 @@
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
+ // Some devices rely on runtime fingerprint generation, so make sure
+ // we've defined it before booting further.
+ Build.ensureFingerprintProperty();
+
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);
@@ -290,6 +297,7 @@
// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
+ mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
}
private void startCoreServices() {
@@ -546,9 +554,9 @@
}
try {
- if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
- mSystemServiceManager.startService(DEVICE_POLICY_MANAGER_SERVICE_CLASS);
- }
+ // Always start the Device Policy Manager, so that the API is compatible with
+ // API8.
+ mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
} catch (Throwable e) {
reportWtf("starting DevicePolicyService", e);
}
@@ -826,6 +834,15 @@
} catch (Throwable e) {
reportWtf("starting Recognition Service", e);
}
+
+ try {
+ if (pm.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) {
+ Slog.i(TAG, "Voice Recognition Service");
+ mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
+ }
+ } catch (Throwable e) {
+ reportWtf("starting Voice Recognition Service", e);
+ }
}
try {
@@ -919,6 +936,12 @@
}
try {
+ mSystemServiceManager.startService(HdmiControlService.class);
+ } catch (Throwable e) {
+ reportWtf("starting HdmiControlService", e);
+ }
+
+ try {
Slog.i(TAG, "TvInputManagerService");
mSystemServiceManager.startService(TvInputManagerService.class);
} catch (Throwable e) {
diff --git a/services/voiceinteraction/Android.mk b/services/voiceinteraction/Android.mk
new file mode 100644
index 0000000..c9e5dd0
--- /dev/null
+++ b/services/voiceinteraction/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.voiceinteraction
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
new file mode 100644
index 0000000..045c0f6
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -0,0 +1,247 @@
+/*
+ * 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.voiceinteraction;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.voice.IVoiceInteractionService;
+import android.service.voice.IVoiceInteractionSession;
+import android.util.Slog;
+import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.SystemService;
+import com.android.server.UiThread;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+
+/**
+ * SystemService that publishes an IVoiceInteractionManagerService.
+ */
+public class VoiceInteractionManagerService extends SystemService {
+
+ static final String TAG = "VoiceInteractionManagerService";
+
+ final Context mContext;
+ final ContentResolver mResolver;
+
+ public VoiceInteractionManagerService(Context context) {
+ super(context);
+ mContext = context;
+ mResolver = context.getContentResolver();
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mServiceStub.systemRunning(isSafeMode());
+ }
+ }
+
+ @Override
+ public void onSwitchUser(int userHandle) {
+ mServiceStub.switchUser(userHandle);
+ }
+
+ // implementation entry point and binder service
+ private final VoiceInteractionManagerServiceStub mServiceStub
+ = new VoiceInteractionManagerServiceStub();
+
+ class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
+
+ VoiceInteractionManagerServiceImpl mImpl;
+
+ private boolean mSafeMode;
+ private int mCurUser;
+
+ public void systemRunning(boolean safeMode) {
+ mSafeMode = safeMode;
+
+ mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
+ UserHandle.ALL, true);
+ new SettingsObserver(UiThread.getHandler());
+
+ synchronized (this) {
+ mCurUser = ActivityManager.getCurrentUser();
+ switchImplementationIfNeededLocked();
+ }
+ }
+
+ public void switchUser(int userHandle) {
+ synchronized (this) {
+ mCurUser = userHandle;
+ switchImplementationIfNeededLocked();
+ }
+ }
+
+ void switchImplementationIfNeededLocked() {
+ if (!mSafeMode) {
+ String curService = Settings.Secure.getStringForUser(
+ mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
+ ComponentName serviceComponent = null;
+ if (curService != null && !curService.isEmpty()) {
+ try {
+ serviceComponent = ComponentName.unflattenFromString(curService);
+ } catch (RuntimeException e) {
+ Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
+ serviceComponent = null;
+ }
+ }
+ if (mImpl == null || mImpl.mUser != mCurUser
+ || !mImpl.mComponent.equals(serviceComponent)) {
+ if (mImpl != null) {
+ mImpl.shutdownLocked();
+ }
+ if (serviceComponent != null) {
+ mImpl = new VoiceInteractionManagerServiceImpl(mContext,
+ UiThread.getHandler(), this, mCurUser, serviceComponent);
+ mImpl.startLocked();
+ } else {
+ mImpl = null;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void startVoiceActivity(Intent intent, String resolvedType,
+ IVoiceInteractionService service, Bundle args) {
+ synchronized (this) {
+ if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) {
+ throw new SecurityException(
+ "Caller is not the current voice interaction service");
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.startVoiceActivityLocked(callingPid, callingUid,
+ intent, resolvedType, args);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
+ public int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+ IVoiceInteractor interactor) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "deliverNewSession without running voice interaction service");
+ return ActivityManager.START_CANCELED;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session,
+ interactor);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump PowerManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+ synchronized (this) {
+ pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n");
+ if (mImpl == null) {
+ pw.println(" (No active implementation)");
+ return;
+ }
+ mImpl.dumpLocked(fd, pw, args);
+ }
+ }
+
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.VOICE_INTERACTION_SERVICE), false, this);
+ }
+
+ @Override public void onChange(boolean selfChange) {
+ synchronized (VoiceInteractionManagerServiceStub.this) {
+ switchImplementationIfNeededLocked();
+ }
+ }
+ }
+
+ PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ return super.onHandleForceStop(intent, packages, uid, doit);
+ }
+
+ @Override
+ public void onHandleUserStop(Intent intent, int userHandle) {
+ super.onHandleUserStop(intent, userHandle);
+ }
+
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ super.onPackageDisappeared(packageName, reason);
+ }
+
+ @Override
+ public void onPackageAppeared(String packageName, int reason) {
+ super.onPackageAppeared(packageName, reason);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ super.onPackageModified(packageName);
+ }
+
+ @Override
+ public void onSomePackagesChanged() {
+ super.onSomePackagesChanged();
+ }
+ };
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
new file mode 100644
index 0000000..6bbd1c1
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -0,0 +1,238 @@
+/*
+ * 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.voiceinteraction;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionService;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.IVoiceInteractionSessionService;
+import android.service.voice.VoiceInteractionService;
+import android.service.voice.VoiceInteractionServiceInfo;
+import android.util.Slog;
+import com.android.internal.app.IVoiceInteractor;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+class VoiceInteractionManagerServiceImpl {
+ final static String TAG = "VoiceInteractionServiceManager";
+
+ final boolean mValid;
+
+ final Context mContext;
+ final Handler mHandler;
+ final Object mLock;
+ final int mUser;
+ final ComponentName mComponent;
+ final IActivityManager mAm;
+ final VoiceInteractionServiceInfo mInfo;
+ final ComponentName mSessionComponentName;
+ boolean mBound = false;
+ IVoiceInteractionService mService;
+
+ SessionConnection mActiveSession;
+
+ final ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mService = IVoiceInteractionService.Stub.asInterface(service);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+ };
+
+ final class SessionConnection implements ServiceConnection {
+ final IBinder mToken = new Binder();
+ final Intent mIntent;
+ final String mResolvedType;
+ final Bundle mArgs;
+ boolean mBound;
+ IVoiceInteractionSessionService mService;
+ IVoiceInteractionSession mSession;
+ IVoiceInteractor mInteractor;
+
+ SessionConnection(Intent intent, String resolvedType, Bundle args) {
+ mIntent = intent;
+ mResolvedType = resolvedType;
+ mArgs = args;
+ Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+ serviceIntent.setComponent(mSessionComponentName);
+ mBound = mContext.bindServiceAsUser(serviceIntent, this,
+ Context.BIND_AUTO_CREATE, new UserHandle(mUser));
+ if (!mBound) {
+ Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mService = IVoiceInteractionSessionService.Stub.asInterface(service);
+ if (mActiveSession == this) {
+ try {
+ mService.newSession(mToken, mArgs);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed making new session", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+
+ public void cancel() {
+ if (mBound) {
+ mContext.unbindService(this);
+ mBound = false;
+ mService = null;
+ mSession = null;
+ mInteractor = null;
+ }
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mToken="); pw.println(mToken);
+ pw.print(prefix); pw.print("mIntent="); pw.println(mIntent);
+ pw.print(" mResolvedType="); pw.println(mResolvedType);
+ pw.print(prefix); pw.print("mArgs="); pw.println(mArgs);
+ pw.print(prefix); pw.print("mBound="); pw.println(mBound);
+ if (mBound) {
+ pw.print(prefix); pw.print("mService="); pw.println(mService);
+ pw.print(prefix); pw.print("mSession="); pw.println(mSession);
+ pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
+ }
+ }
+ };
+
+ VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock,
+ int userHandle, ComponentName service) {
+ mContext = context;
+ mHandler = handler;
+ mLock = lock;
+ mUser = userHandle;
+ mComponent = service;
+ mAm = ActivityManagerNative.getDefault();
+ VoiceInteractionServiceInfo info;
+ try {
+ info = new VoiceInteractionServiceInfo(context.getPackageManager(), service);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Voice interaction service not found: " + service);
+ mInfo = null;
+ mSessionComponentName = null;
+ mValid = false;
+ return;
+ }
+ mInfo = info;
+ if (mInfo.getParseError() != null) {
+ Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError());
+ mSessionComponentName = null;
+ mValid = false;
+ return;
+ }
+ mValid = true;
+ mSessionComponentName = new ComponentName(service.getPackageName(),
+ mInfo.getSessionService());
+ }
+
+ public void startVoiceActivityLocked(int callingPid, int callingUid, Intent intent,
+ String resolvedType, Bundle args) {
+ if (mActiveSession != null) {
+ mActiveSession.cancel();
+ mActiveSession = null;
+ }
+ mActiveSession = new SessionConnection(intent, resolvedType, args);
+ intent.addCategory(Intent.CATEGORY_VOICE);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+
+ public int deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
+ IVoiceInteractionSession session, IVoiceInteractor interactor) {
+ try {
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "deliverNewSession does not match active session");
+ return ActivityManager.START_CANCELED;
+ }
+ mActiveSession.mSession = session;
+ mActiveSession.mInteractor = interactor;
+ return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
+ mActiveSession.mIntent, mActiveSession.mResolvedType,
+ mActiveSession.mSession, mActiveSession.mInteractor,
+ 0, null, null, null, mUser);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Unexpected remote error", e);
+ }
+ }
+
+ public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!mValid) {
+ pw.print(" NOT VALID: ");
+ if (mInfo == null) {
+ pw.println("no info");
+ } else {
+ pw.println(mInfo.getParseError());
+ }
+ return;
+ }
+ pw.print(" mComponent="); pw.println(mComponent.flattenToShortString());
+ pw.print(" Session service="); pw.println(mInfo.getSessionService());
+ pw.print(" Settings activity="); pw.println(mInfo.getSettingsActivity());
+ pw.print(" mBound="); pw.print(mBound); pw.print(" mService="); pw.println(mService);
+ if (mActiveSession != null) {
+ pw.println(" Active session:");
+ mActiveSession.dump(" ", pw);
+ }
+ }
+
+ void startLocked() {
+ Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+ intent.setComponent(mComponent);
+ mBound = mContext.bindServiceAsUser(intent, mConnection,
+ Context.BIND_AUTO_CREATE, new UserHandle(mUser));
+ if (!mBound) {
+ Slog.w(TAG, "Failed binding to voice interaction service " + mComponent);
+ }
+ }
+
+ void shutdownLocked() {
+ if (mBound) {
+ mContext.unbindService(mConnection);
+ mBound = false;
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
index 4a9ae39..96069213 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
+++ b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
@@ -23,6 +23,7 @@
* Data connection real time information
*
* TODO: How to handle multiple subscriptions?
+ * @hide
*/
public class DataConnectionRealTimeInfo implements Parcelable {
private long mTime; // Time the info was collected since boot in nanos;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 7c5c648..59ec6f5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -18,6 +18,7 @@
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -199,7 +200,67 @@
*/
public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO = 0x00002000;
+ private final Handler mHandler;
+
public PhoneStateListener() {
+ this(Looper.myLooper());
+ }
+
+ /** @hide */
+ public PhoneStateListener(Looper looper) {
+ mHandler = new Handler(looper) {
+ public void handleMessage(Message msg) {
+ //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what)
+ // + " msg=" + msg);
+ switch (msg.what) {
+ case LISTEN_SERVICE_STATE:
+ PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
+ break;
+ case LISTEN_SIGNAL_STRENGTH:
+ PhoneStateListener.this.onSignalStrengthChanged(msg.arg1);
+ break;
+ case LISTEN_MESSAGE_WAITING_INDICATOR:
+ PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0);
+ break;
+ case LISTEN_CALL_FORWARDING_INDICATOR:
+ PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0);
+ break;
+ case LISTEN_CELL_LOCATION:
+ PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj);
+ break;
+ case LISTEN_CALL_STATE:
+ PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
+ break;
+ case LISTEN_DATA_CONNECTION_STATE:
+ PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2);
+ PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1);
+ break;
+ case LISTEN_DATA_ACTIVITY:
+ PhoneStateListener.this.onDataActivity(msg.arg1);
+ break;
+ case LISTEN_SIGNAL_STRENGTHS:
+ PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
+ break;
+ case LISTEN_OTASP_CHANGED:
+ PhoneStateListener.this.onOtaspChanged(msg.arg1);
+ break;
+ case LISTEN_CELL_INFO:
+ PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
+ break;
+ case LISTEN_PRECISE_CALL_STATE:
+ PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
+ break;
+ case LISTEN_PRECISE_DATA_CONNECTION_STATE:
+ PhoneStateListener.this.onPreciseDataConnectionStateChanged(
+ (PreciseDataConnectionState)msg.obj);
+ break;
+ case LISTEN_DATA_CONNECTION_REAL_TIME_INFO:
+ PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
+ (DataConnectionRealTimeInfo)msg.obj);
+ break;
+ }
+ }
+ };
}
/**
@@ -424,56 +485,4 @@
dcRtInfo).sendToTarget();
}
};
-
- Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what) + " msg=" + msg);
- switch (msg.what) {
- case LISTEN_SERVICE_STATE:
- PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
- break;
- case LISTEN_SIGNAL_STRENGTH:
- PhoneStateListener.this.onSignalStrengthChanged(msg.arg1);
- break;
- case LISTEN_MESSAGE_WAITING_INDICATOR:
- PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0);
- break;
- case LISTEN_CALL_FORWARDING_INDICATOR:
- PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0);
- break;
- case LISTEN_CELL_LOCATION:
- PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj);
- break;
- case LISTEN_CALL_STATE:
- PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
- break;
- case LISTEN_DATA_CONNECTION_STATE:
- PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2);
- PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1);
- break;
- case LISTEN_DATA_ACTIVITY:
- PhoneStateListener.this.onDataActivity(msg.arg1);
- break;
- case LISTEN_SIGNAL_STRENGTHS:
- PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
- break;
- case LISTEN_OTASP_CHANGED:
- PhoneStateListener.this.onOtaspChanged(msg.arg1);
- break;
- case LISTEN_CELL_INFO:
- PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
- break;
- case LISTEN_PRECISE_CALL_STATE:
- PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
- break;
- case LISTEN_PRECISE_DATA_CONNECTION_STATE:
- PhoneStateListener.this.onPreciseDataConnectionStateChanged((PreciseDataConnectionState)msg.obj);
- break;
- case LISTEN_DATA_CONNECTION_REAL_TIME_INFO:
- PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
- (DataConnectionRealTimeInfo)msg.obj);
- break;
- }
- }
- };
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d5c7caa..407a8d1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1094,6 +1094,10 @@
public static final int SIM_STATE_NETWORK_LOCKED = 4;
/** SIM card state: Ready */
public static final int SIM_STATE_READY = 5;
+ /** SIM card state: SIM Card Error, Sim Card is present but faulty
+ *@hide
+ */
+ public static final int SIM_STATE_CARD_IO_ERROR = 6;
/**
* @return true if a ICC card is present
@@ -1120,6 +1124,7 @@
* @see #SIM_STATE_PUK_REQUIRED
* @see #SIM_STATE_NETWORK_LOCKED
* @see #SIM_STATE_READY
+ * @see #SIM_STATE_CARD_IO_ERROR
*/
public int getSimState() {
String prop = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE);
@@ -1138,6 +1143,9 @@
else if ("READY".equals(prop)) {
return SIM_STATE_READY;
}
+ else if ("CARD_IO_ERROR".equals(prop)) {
+ return SIM_STATE_CARD_IO_ERROR;
+ }
else {
return SIM_STATE_UNKNOWN;
}
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index 236bb2f..8029713 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -28,6 +28,8 @@
public static final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY";
/* ABSENT means ICC is missing */
public static final String INTENT_VALUE_ICC_ABSENT = "ABSENT";
+ /* CARD_IO_ERROR means for three consecutive times there was SIM IO error */
+ static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = "CARD_IO_ERROR";
/* LOCKED means ICC is locked by pin or by network */
public static final String INTENT_VALUE_ICC_LOCKED = "LOCKED";
/* READY means ICC is ready to access */
@@ -63,7 +65,8 @@
NETWORK_LOCKED,
READY,
NOT_READY,
- PERM_DISABLED;
+ PERM_DISABLED,
+ CARD_IO_ERROR;
public boolean isPinLocked() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
@@ -72,7 +75,7 @@
public boolean iccCardExist() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)
|| (this == NETWORK_LOCKED) || (this == READY)
- || (this == PERM_DISABLED));
+ || (this == PERM_DISABLED) || (this == CARD_IO_ERROR));
}
}
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 0ad3456..5c2583b 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -867,5 +867,13 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".ProjectionClippingActivity"
+ android:label="Reordering/Projection Clipping">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/HwAccelerationTest/res/drawable/round_rect_background.xml b/tests/HwAccelerationTest/res/drawable/round_rect_background.xml
new file mode 100644
index 0000000..14d4073
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/round_rect_background.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <solid android:color="#eee" />
+ <corners android:radius="30dp" />
+</shape>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/layout/projection_clipping.xml b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
new file mode 100644
index 0000000..7177fc8f
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <FrameLayout
+ android:translationX="50dp"
+ android:translationY="50dp"
+ android:elevation="30dp"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ android:background="@drawable/round_rect_background">
+ <View
+ android:id="@+id/clickable1"
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:background="?android:attr/selectableItemBackground"/>
+ <View
+ android:id="@+id/clickable2"
+ android:translationX="50dp"
+ android:translationY="10dp"
+ android:layout_width="150dp"
+ android:layout_height="100dp"
+ android:background="?android:attr/selectableItemBackground"/>
+ </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
new file mode 100644
index 0000000..2ae960b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
@@ -0,0 +1,27 @@
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.RenderNode;
+import android.view.View;
+
+public class ProjectionClippingActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.projection_clipping);
+ View.OnClickListener listener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // woo! nothing!
+ }
+ };
+ findViewById(R.id.clickable1).setOnClickListener(listener);
+ findViewById(R.id.clickable2).setOnClickListener(listener);
+ }
+}
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
index bcf3ae6..0be6755 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,26 +16,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
<viewport
- android:viewportWidth="7.30625"
- android:viewportHeight="12.25"/>
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625" />
<group>
<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
+ android:name="one"
+ android:fill="#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"
- android:fill="#ffff00"
- />
-
-
+ l -5.046875,0.0 0.0,-1.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
+ android:name="two"
+ android:fill="#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
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -42,23 +42,20 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
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="#ffff00"
- android:fillOpacity="0"
- />
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
</group>
<group>
<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
+ android:name="one"
+ android:fill="#ffff00"
+ android:fillOpacity="0"
+ 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="#ffff00"
- android:fillOpacity="0"
- />
+l -5.046875,0.0 0.0,-1.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
+ android:name="two"
+ android:fill="#ffff00"
+ 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
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -66,14 +63,13 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
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="#ffff00"
- />
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
</group>
<group>
<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
+ android:name="two"
+ android:fill="#ffff00"
+ 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
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -81,12 +77,12 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
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="#ffff00"
- />
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
<path
- android:name="three"
- android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
+ android:name="three"
+ android:fill="#ffff00"
+ android:fillOpacity="0"
+ android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
@@ -98,15 +94,14 @@
q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
- q -0.40625,0.5 -1.171875,0.6875Z"
- android:fill="#ffff00"
- android:fillOpacity="0"
- />
+ q -0.40625,0.5 -1.171875,0.6875Z" />
</group>
<group>
<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
+ android:name="two"
+ android:fill="#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
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -114,13 +109,11 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
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="#ffff00"
- android:fillOpacity="0"
- />
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
<path
- android:name="three"
- android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
+ android:name="three"
+ android:fill="#ffff00"
+ android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
@@ -132,16 +125,14 @@
q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
- q -0.40625,0.5 -1.171875,0.6875Z"
- android:fill="#ffff00"
- />
+ q -0.40625,0.5 -1.171875,0.6875Z" />
</group>
+ <animation
+ android:durations="2000,0,2000"
+ android:sequence="one,one,three,three" />
+ <animation
+ android:durations="2000,0,2000"
+ android:sequence="two,two,two,two" />
- <animation
- android:sequence="one,one,three,three"
- android:durations="2000,0,2000"/>
- <animation
- android:sequence="two,two,two,two"
- android:durations="2000,0,2000"/>
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
index 09934de..b3c91a88 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,27 +16,29 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
-
- <viewport android:viewportWidth="200"
- android:viewportHeight="200"/>
+ <viewport
+ android:viewportHeight="200"
+ android:viewportWidth="200" />
<group>
<path
- android:name="arrow"
- android:pathData="M 20,20 l 60,0 0,140 -60,0 z M 120,20 l 60,0 0,140 -60,0 z"
- android:fill="#ffffffff"/>
+ android:name="arrow"
+ android:fill="#ffffffff"
+ android:pathData="M 20,20 l 60,0 0,140 -60,0 z M 120,20 l 60,0 0,140 -60,0 z" />
</group>
<group>
<path
- android:name="house"
- android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
- android:fill="#ffffffff"
- android:rotation="90"
- android:pivotX="100"
- android:pivotY="100"/>
+ android:name="house"
+ android:fill="#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"
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="90" />
</group>
- <animation android:sequence="arrow,house"/>
-</vector>
+
+ <animation android:sequence="arrow,house" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
index f17f67a..7aca169 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
@@ -27,88 +27,87 @@
<group>
<path
android:name="bar3"
- 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"
- android:fill="#FFFFFFFF" />
+ android:fill="#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: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"
- android:fill="#FF555555" />
+ android:fill="#FF555555"
+ 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: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"
- android:fill="#FF555555" />
+ android:fill="#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: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"
- android:fill="#FF555555" />
+ android:fill="#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>
- <group>
+ <group>
<path
android:name="bar3"
- 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"
- android:fill="#FFFFFFFF" />
+ android:fill="#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: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"
- android:fill="#FFFFFFFF" />
+ android:fill="#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: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"
- android:fill="#FF555555" />
+ android:fill="#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: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"
- android:fill="#FF555555" />
+ android:fill="#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>
-
- <group>
+ <group>
<path
android:name="bar3"
- 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"
- android:fill="#FFFFFFFF" />
+ android:fill="#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: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"
- android:fill="#FFFFFFFF" />
+ android:fill="#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: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"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ 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: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"
- android:fill="#FF555555" />
+ android:fill="#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>
-
- <group>
+ <group>
<path
android:name="bar3"
- 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"
- android:fill="#FFFFFFFF" />
+ android:fill="#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: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"
- android:fill="#FFFFFFFF" />
+ android:fill="#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: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"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ 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: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"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ 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>
- <animation
- android:sequence="bar0,bar0,bar0,bar0"
- android:durations="500,500,500"/>
- <animation
- android:sequence="bar1,bar1,bar1,bar1"
- android:durations="500,500,500"/>
- <animation
- android:sequence="bar2,bar2,bar2,bar2"
- android:durations="500,500,500"/>
- <animation
- android:sequence="bar3,bar3,bar3,bar3"
- android:durations="500,500,500"/>
-</vector>
+ <animation
+ android:durations="500,500,500"
+ android:sequence="bar0,bar0,bar0,bar0" />
+ <animation
+ android:durations="500,500,500"
+ android:sequence="bar1,bar1,bar1,bar1" />
+ <animation
+ android:durations="500,500,500"
+ android:sequence="bar2,bar2,bar2,bar2" />
+ <animation
+ android:durations="500,500,500"
+ android:sequence="bar3,bar3,bar3,bar3" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
index 8787b34..a4403c5 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -26,29 +26,28 @@
<group>
<path
android:name="battery"
- 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:fill="#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:rotation="0"
android:stroke="#ff8833"
- android:strokeWidth="1"
- android:rotation="0"/>
- <path
+ android:strokeWidth="1" />
+ <path
android:name="spark"
- 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"
- android:fill="#FFFF0000" />
-
+ android:fill="#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>
<group>
<path
android:name="battery"
- 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:fill="#ff8833"
+ 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:rotation="0"
android:stroke="#3388ff"
- android:strokeWidth="1"
- android:rotation="0" />
+ android:strokeWidth="1" />
<path
android:name="spark"
- 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"
- android:fill="#FFFF0000" />
+ android:fill="#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>
<animation
@@ -58,5 +57,4 @@
android:durations="2000"
android:sequence="battery,battery" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 89748d5..207879d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,76 +16,72 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
-
- <viewport android:viewportWidth="600"
- android:viewportHeight="600"/>
+ <viewport
+ android:viewportHeight="600"
+ android:viewportWidth="600" />
<group>
<path
- android:name="pie1"
- android:pathData="M300,70 a230,230 0 1,0 1,0 z"
- android:stroke="#FF00FF00"
- android:strokeWidth="70"
- android:trimPathStart="0"
- android:trimPathEnd=".75"
- android:trimPathOffset="0"/>
-
+ android:name="pie1"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="70"
+ android:trimPathEnd=".75"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
<path
- android:name="v"
- android:pathData="M300,70 l 0,-70 70,70 -70,70z"
- android:fill="#FF00FF00"
- android:pivotX="300"
- android:pivotY="300"
- android:rotation="0"
- />
+ android:name="v"
+ android:fill="#FF00FF00"
+ android:pathData="M300,70 l 0,-70 70,70 -70,70z"
+ android:pivotX="300"
+ android:pivotY="300"
+ android:rotation="0" />
</group>
-
<group>
<path
- android:name="v"
- android:pathData="M300,70 l 0,-70 70,70 -70,70z"
- android:pivotX="300"
- android:pivotY="300"
- android:rotation="360"/>
+ android:name="v"
+ android:pathData="M300,70 l 0,-70 70,70 -70,70z"
+ android:pivotX="300"
+ android:pivotY="300"
+ android:rotation="360" />
<path
- android:name="pie2"
- android:pathData="M300,70 a230,230 0 1,0 1,0 z"
- android:stroke="#FF00FF00"
- android:strokeWidth="70"
- android:rotation="360"
- android:pivotX="300"
- android:pivotY="300"
- android:trimPathStart="0"
- android:trimPathEnd=".5"
- android:trimPathOffset="0"
- android:strokeLineCap="round"
- />
+ android:name="pie2"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+ android:pivotX="300"
+ android:pivotY="300"
+ android:rotation="360"
+ android:stroke="#FF00FF00"
+ android:strokeLineCap="round"
+ android:strokeWidth="70"
+ android:trimPathEnd=".5"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
</group>
- <animation android:sequence="pie1,pie2"
- android:durations="2000"
- android:startOffset="500"
- android:repeatCount="-1"
- android:repeatStyle="forward"
- android:animate="easeInOut"
- />
- <animation android:sequence="v,v"
- android:durations="2000"
- android:startOffset="500"
- android:repeatCount="-1"
- android:repeatStyle="forward"
- android:animate="easeInOut"
- />
- <animation android:sequence="pie1,pie2"
- android:durations="2800"
- android:startOffset="500"
- android:limitTo="trimPathEnd"
- android:repeatCount="-1"
- android:repeatStyle="reverse"
- android:animate="easeInOut"
- />
+ <animation
+ android:animate="easeInOut"
+ android:durations="2000"
+ android:repeatCount="-1"
+ android:repeatStyle="forward"
+ android:sequence="pie1,pie2"
+ android:startOffset="500" />
+ <animation
+ android:animate="easeInOut"
+ android:durations="2000"
+ android:repeatCount="-1"
+ android:repeatStyle="forward"
+ android:sequence="v,v"
+ android:startOffset="500" />
+ <animation
+ android:animate="easeInOut"
+ android:durations="2800"
+ android:limitTo="trimPathEnd"
+ android:repeatCount="-1"
+ android:repeatStyle="reverse"
+ android:sequence="pie1,pie2"
+ android:startOffset="500" />
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
index 43dda52..4a2ed90 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,68 +16,64 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
-
- <viewport android:viewportWidth="600"
- android:viewportHeight="400"/>
+ <viewport
+ android:viewportHeight="400"
+ android:viewportWidth="600" />
<group>
<path
- android:name="pie1"
- android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
- android:fill="#ffffffff"
- android:stroke="#FF00FF00"
- android:strokeWidth="1"/>
-
+ android:name="pie1"
+ android:fill="#ffffffff"
+ android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="1" />
<path
- android:name="half"
- android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
- android:fill="#FFFF0000"
- android:stroke="#FF0000FF"
- android:strokeWidth="5"
- android:rotation="0"
- android:pivotX="300"
- android:pivotY="200"/>
+ android:name="half"
+ android:fill="#FFFF0000"
+ android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+ android:pivotX="300"
+ android:pivotY="200"
+ android:rotation="0"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="5" />
</group>
-
<group>
<path
- android:name="pie2"
- android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
- android:fill="#ffff0000"
- android:stroke="#FF00FF00"
- android:strokeWidth="10"
- android:rotation="360"
- android:pivotX="300"
- android:pivotY="200"/>
-
+ android:name="pie2"
+ android:fill="#ffff0000"
+ android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+ android:pivotX="300"
+ android:pivotY="200"
+ android:rotation="360"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
<path
- android:name="half"
- android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
- android:fill="#FFFFFF00"
- android:stroke="#FF0000FF"
- android:strokeWidth="5"
- android:rotation="-360"
- android:pivotX="300"
- android:pivotY="200"/>
+ android:name="half"
+ android:fill="#FFFFFF00"
+ android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+ android:pivotX="300"
+ android:pivotY="200"
+ android:rotation="-360"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="5" />
</group>
- <animation android:sequence="pie1,pie2"
- android:durations="1000"
- android:startOffset="500"
- android:repeatCount="2"
- android:repeatStyle="forward"
- android:animate="easeInOut"
- />
- <animation android:sequence="half,half"
- android:durations="1000"
- android:startOffset="500"
- android:repeatCount="5"
- android:repeatStyle="forward"
- android:animate="easeInOut"
- />
+ <animation
+ android:animate="easeInOut"
+ android:durations="1000"
+ android:repeatCount="2"
+ android:repeatStyle="forward"
+ android:sequence="pie1,pie2"
+ android:startOffset="500" />
+ <animation
+ android:animate="easeInOut"
+ android:durations="1000"
+ android:repeatCount="5"
+ android:repeatStyle="forward"
+ android:sequence="half,half"
+ android:startOffset="500" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
index 0f1f149..6ebd56b 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,40 +16,39 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="800"
- android:viewportHeight="500"/>
+ <viewport
+ android:viewportHeight="500"
+ android:viewportWidth="800" />
<group>
<path
- android:name="pie1"
- android:pathData="M200,450 l 50,-25
+ android:name="pie1"
+ android:pathData="M200,450 l 50,-25
a25,25 -30 0,1 100,-50 l 50,-25
a25,50 -30 0,1 100,-50 l 50,-25
a25,75 -30 0,1 100,-50 l 50,-25
a25,100 -30 0,1 100,-50 l 50,-25"
- android:stroke="#FF00FF00"
- android:strokeWidth="10"/>
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
</group>
-
<group>
<path
- android:name="pie2"
- android:pathData="M200,350 l 50,-25
+ android:name="pie2"
+ android:pathData="M200,350 l 50,-25
a25,12 -30 0,1 100,-50 l 50,-25
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:stroke="#FF00FF00"
- android:strokeWidth="10"
- android:rotation="20"
- android:pivotX="90"
- android:pivotY="100"/>
-
+ android:pivotX="90"
+ android:pivotY="100"
+ android:rotation="20"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
</group>
- <animation android:sequence="pie1,pie2"/>
+ <animation android:sequence="pie1,pie2" />
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
index 6bc946f..3c92d25 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,34 +16,33 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="500"
- android:viewportHeight="400"/>
+ <viewport
+ android:viewportHeight="400"
+ android:viewportWidth="500" />
<group>
<path
- android:name="arrow"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:fill="#ffffffff"
- android:stroke="#FFFF0000"
- android:strokeWidth="1"/>
+ android:name="arrow"
+ android:fill="#ffffffff"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="1" />
</group>
-
<group>
<path
- android:name="house"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:fill="#ff440000"
- android:stroke="#FFFF0000"
- android:strokeWidth="10"
- android:rotation="180"
- android:pivotX="250"
- android:pivotY="200"/>
+ android:name="house"
+ android:fill="#ff440000"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:pivotX="250"
+ android:pivotY="200"
+ android:rotation="180"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house"/>
+ <animation android:sequence="arrow,house" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
index c9c8e8a..7e757a5 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,32 +16,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="200"
- android:viewportHeight="200"/>
+ <viewport
+ android:viewportHeight="200"
+ android:viewportWidth="200" />
<group>
<path
- android:name="arrow"
- android:pathData="M 100,10 v 180 M 10,100 h 180"
- android:stroke="#FF00FF00"
- android:strokeWidth="1"/>
+ android:name="arrow"
+ android:pathData="M 100,10 v 180 M 10,100 h 180"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="1" />
</group>
-
<group>
<path
- android:name="house"
- android:pathData="M 100,10 v 90 M 10,100 h 90"
- android:stroke="#FF00FF00"
- android:strokeWidth="10"
- android:rotation="360"
- android:pivotX="100"
- android:pivotY="100"/>
+ android:name="house"
+ android:pathData="M 100,10 v 90 M 10,100 h 90"
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="360"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house"/>
+ <animation android:sequence="arrow,house" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
index 83dfbd2..69212f5 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,31 +16,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="500"
- android:viewportHeight="400"/>
+ <viewport
+ android:viewportHeight="400"
+ android:viewportWidth="500" />
<group>
<path
- android:name="arrow"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:stroke="#FFFFFF00"
- android:strokeWidth="10"/>
+ android:name="arrow"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:stroke="#FFFFFF00"
+ android:strokeWidth="10" />
</group>
-
<group>
<path
- android:name="house"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:strokeWidth="10"
- android:rotation="360"
- android:pivotX="250"
- android:pivotY="200"/>
+ android:name="house"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:pivotX="250"
+ android:pivotY="200"
+ android:rotation="360"
+ android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house"/>
+ <animation android:sequence="arrow,house" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
index 013254f..2dca48d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,31 +16,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="1000"
- android:viewportHeight="800"/>
+ <viewport
+ android:viewportHeight="800"
+ android:viewportWidth="1000" />
<group>
<path
- android:name="arrow"
- android:pathData="M10,300 Q400,50 600,300 T1000,300"
- android:stroke="#FF00FFFF"
- android:strokeWidth="40"/>
+ android:name="arrow"
+ android:pathData="M10,300 Q400,50 600,300 T1000,300"
+ android:stroke="#FF00FFFF"
+ android:strokeWidth="40" />
</group>
-
<group>
<path
- android:name="house"
- android:pathData="M10,300 Q400,550 600,300 T1000,300"
- android:stroke="#FFFF0000"
- android:strokeWidth="60"
- android:pivotX="90"
- android:pivotY="100"/>
+ android:name="house"
+ android:pathData="M10,300 Q400,550 600,300 T1000,300"
+ android:pivotX="90"
+ android:pivotY="100"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="60" />
</group>
- <animation android:sequence="arrow,house"/>
+ <animation android:sequence="arrow,house" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
index aba7e5f..b8af7e2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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,23 +16,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="480"
- android:viewportHeight="480"/>
+ <viewport
+ android:viewportHeight="480"
+ android:viewportWidth="480" />
<group>
<path
- android:name="edit"
- android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+ android:name="edit"
+ android:fill="#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:fill="#FF00FFFF"
- android:strokeWidth="10"/>
+ android:stroke="#FF000000"
+ android:strokeWidth="10" />
</group>
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
index 8897181..22ce795 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,17 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- 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"
- android:fill="#FF000000"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fill="#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>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
index 2c7ebbd..042173c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,17 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- 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"
- android:fill="#FF000000"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fill="#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>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
index e4cf78c..6b6f43d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,17 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- 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"
- android:fill="#FF000000"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fill="#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>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
index cec12ba..ba8ebca 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,21 +14,22 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z"
- android:fillOpacity="0.9"
- />
-<path
- android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z"
- android:fillOpacity="0.9"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fillOpacity="0.9"
+ android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" />
+ <path
+ android:fillOpacity="0.9"
+ android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
index 5fe1fb6..896a938 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,17 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- 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"
- android:fill="#FF000000"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fill="#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>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
index 6beb9d8..a9091ab 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,19 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="128dp"
-android:height="128dp"/>
- <viewport android:viewportWidth="512"
- android:viewportHeight="512"/>
+ <size
+ android:height="128dp"
+ android:width="128dp" />
-<group>
-<path
- android:name="002b"
- android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
- android:stroke="#FF0000FF"
- android:strokeWidth="4"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="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:strokeWidth="4" />
+ </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 2c1a28e..ab58c06 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,19 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="128dp"
-android:height="128dp"/>
- <viewport android:viewportWidth="512"
- android:viewportHeight="512"/>
+ <size
+ android:height="128dp"
+ android:width="128dp" />
-<group>
-<path
- android:name="002b"
- android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
- android:stroke="#FF0000FF"
- android:strokeWidth="4"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="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:strokeWidth="4" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VoiceInteraction/Android.mk b/tests/VoiceInteraction/Android.mk
new file mode 100644
index 0000000..8decca7
--- /dev/null
+++ b/tests/VoiceInteraction/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := VoiceInteraction
+
+include $(BUILD_PACKAGE)
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
new file mode 100644
index 0000000..ac0f701
--- /dev/null
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.voiceinteraction">
+
+ <application>
+ <activity android:name="VoiceInteractionMain" android:label="Voice Interaction">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <service android:name="MainInteractionService"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":interactor">
+ <meta-data android:name="android.voice_interaction"
+ android:resource="@xml/interaction_service" />
+ <intent-filter>
+ <action android:name="android.service.voice.VoiceInteractionService" />
+ </intent-filter>
+ </service>
+ <service android:name="MainInteractionSessionService"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":session">
+ </service>
+ <activity android:name="TestInteractionActivity" android:label="Voice Interaction Target">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/VoiceInteraction/res/layout/main.xml b/tests/VoiceInteraction/res/layout/main.xml
new file mode 100644
index 0000000..3d7a418
--- /dev/null
+++ b/tests/VoiceInteraction/res/layout/main.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <Button android:id="@+id/start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/start"
+ />
+
+</LinearLayout>
+
+
diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml
new file mode 100644
index 0000000..2abf65194
--- /dev/null
+++ b/tests/VoiceInteraction/res/layout/test_interaction.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="We are interacting!"
+ />
+
+ <TextView android:id="@+id/log"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:layout_marginTop="10dp"
+ android:textSize="12sp"
+ android:textColor="#ffffffff"
+ />
+
+</LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
new file mode 100644
index 0000000..12edb31
--- /dev/null
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?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="start">Start!</string>
+
+</resources>
+
diff --git a/tests/VoiceInteraction/res/xml/interaction_service.xml b/tests/VoiceInteraction/res/xml/interaction_service.xml
new file mode 100644
index 0000000..45bd994d
--- /dev/null
+++ b/tests/VoiceInteraction/res/xml/interaction_service.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.
+ */
+-->
+
+<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:sessionService="com.android.test.voiceinteraction.MainInteractionSessionService" />
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
new file mode 100644
index 0000000..008d97b
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.voiceinteraction;
+
+import android.content.Intent;
+import android.service.voice.VoiceInteractionService;
+import android.util.Log;
+
+public class MainInteractionService extends VoiceInteractionService {
+ static final String TAG = "MainInteractionService";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i(TAG, "Creating " + this);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ startVoiceActivity(new Intent(this, TestInteractionActivity.class), null);
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
new file mode 100644
index 0000000..0fc563b
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -0,0 +1,56 @@
+/*
+ * 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.test.voiceinteraction;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.util.Log;
+
+public class MainInteractionSession extends VoiceInteractionSession {
+ static final String TAG = "MainInteractionSession";
+
+ final Bundle mArgs;
+
+ MainInteractionSession(Context context, Bundle args) {
+ super(context);
+ mArgs = args;
+ }
+
+ @Override
+ public boolean[] onGetSupportedCommands(Caller caller, String[] commands) {
+ return new boolean[commands.length];
+ }
+
+ @Override
+ public void onConfirm(Caller caller, Request request, String prompt, Bundle extras) {
+ Log.i(TAG, "onConform: prompt=" + prompt + " extras=" + extras);
+ request.sendConfirmResult(true, null);
+ }
+
+ @Override
+ public void onCommand(Caller caller, Request request, String command, Bundle extras) {
+ Log.i(TAG, "onCommand: command=" + command + " extras=" + extras);
+ request.sendCommandResult(true, null);
+ }
+
+ @Override
+ public void onCancel(Request request) {
+ Log.i(TAG, "onCancel");
+ request.sendCancelResult();
+ }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
new file mode 100644
index 0000000..8864d71
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.voiceinteraction;
+
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.service.voice.VoiceInteractionSessionService;
+
+public class MainInteractionSessionService extends VoiceInteractionSessionService {
+ @Override
+ public VoiceInteractionSession onNewSession(Bundle args) {
+ return new MainInteractionSession(this, args);
+ }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
new file mode 100644
index 0000000..9c772ff
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.voiceinteraction;
+
+import android.app.Activity;
+import android.app.VoiceInteractor;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestInteractionActivity extends Activity {
+ static final String TAG = "TestInteractionActivity";
+
+ VoiceInteractor mInteractor;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (!isVoiceInteraction()) {
+ Log.w(TAG, "Not running as a voice interaction!");
+ finish();
+ return;
+ }
+
+ setContentView(R.layout.test_interaction);
+
+ mInteractor = getVoiceInteractor();
+ VoiceInteractor.ConfirmationRequest req = new VoiceInteractor.ConfirmationRequest(
+ "This is a confirmation", null) {
+ @Override
+ public void onCancel() {
+ Log.i(TAG, "Canceled!");
+ getActivity().finish();
+ }
+
+ @Override
+ public void onConfirmationResult(boolean confirmed, Bundle result) {
+ Log.i(TAG, "Confirmation result: confirmed=" + confirmed + " result=" + result);
+ getActivity().finish();
+ }
+ };
+ mInteractor.submitRequest(req);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java
new file mode 100644
index 0000000..5d212a4
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java
@@ -0,0 +1,49 @@
+/*
+ * 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.test.voiceinteraction;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+public class VoiceInteractionMain extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.main);
+ findViewById(R.id.start).setOnClickListener(mStartListener);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ View.OnClickListener mStartListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ startService(new Intent(VoiceInteractionMain.this, MainInteractionService.class));
+ }
+ };
+}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 6d9d62e..d0581f6 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -2462,7 +2462,7 @@
status_t
writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
- const char* startTag, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
+ const Vector<String8>& startTags, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
{
status_t err;
ResXMLTree tree;
@@ -2476,15 +2476,18 @@
tree.restart();
- if (startTag != NULL) {
+ if (!startTags.isEmpty()) {
bool haveStart = false;
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code != ResXMLTree::START_TAG) {
continue;
}
String8 tag(tree.getElementName(&len));
- if (tag == startTag) {
- haveStart = true;
+ const size_t numStartTags = startTags.size();
+ for (size_t i = 0; i < numStartTags; i++) {
+ if (tag == startTags[i]) {
+ haveStart = true;
+ }
}
break;
}
@@ -2571,15 +2574,17 @@
for (size_t k=0; k<K; k++) {
const sp<AaptDir>& d = dirs.itemAt(k);
const String8& dirName = d->getLeaf();
+ Vector<String8> startTags;
const char* startTag = NULL;
const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
tagAttrPairs = &kLayoutTagAttrPairs;
} else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
- startTag = "PreferenceScreen";
+ startTags.add(String8("PreferenceScreen"));
+ startTags.add(String8("preference-headers"));
tagAttrPairs = &kXmlTagAttrPairs;
} else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
- startTag = "menu";
+ startTags.add(String8("menu"));
tagAttrPairs = NULL;
} else {
continue;
@@ -2592,7 +2597,7 @@
const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
const size_t M = files.size();
for (size_t j=0; j<M; j++) {
- err = writeProguardForXml(keep, files.valueAt(j), startTag, tagAttrPairs);
+ err = writeProguardForXml(keep, files.valueAt(j), startTags, tagAttrPairs);
if (err < 0) {
return err;
}
diff --git a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
index 22232f3..0dddf3d 100644
--- a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
@@ -23,7 +23,6 @@
import com.android.internal.view.menu.MenuView;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.util.AttributeSet;
@@ -45,7 +44,7 @@
public class MenuInflater_Delegate {
@LayoutlibDelegate
- /*package*/ static void emptyMethod(MenuInflater thisInflater, MenuItem menuItem,
+ /*package*/ static void registerMenu(MenuInflater thisInflater, MenuItem menuItem,
AttributeSet attrs) {
if (menuItem instanceof BridgeMenuItemImpl) {
Context context = thisInflater.getContext();
@@ -67,9 +66,9 @@
}
@LayoutlibDelegate
- /*package*/ static void emptyMethod(MenuInflater thisInflater, SubMenu subMenu,
+ /*package*/ static void registerMenu(MenuInflater thisInflater, SubMenu subMenu,
AttributeSet parser) {
- emptyMethod(thisInflater, subMenu.getItem(), parser);
+ registerMenu(thisInflater, subMenu.getItem(), parser);
}
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 986b911..813a895 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -143,7 +143,7 @@
"android.view.ViewRootImpl#isInTouchMode",
"android.view.WindowManagerGlobal#getWindowManagerService",
"android.view.inputmethod.InputMethodManager#getInstance",
- "android.view.MenuInflater#emptyMethod",
+ "android.view.MenuInflater#registerMenu",
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
"com.android.internal.util.XmlUtils#convertValueToInt",
"com.android.internal.textservice.ITextServicesManager$Stub#asInterface",