Merge "Cache media/nomedia paths"
diff --git a/Android.mk b/Android.mk
index 781d5d1..0865d24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -89,6 +89,8 @@
core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
core/java/android/app/backup/IRestoreObserver.aidl \
core/java/android/app/backup/IRestoreSession.aidl \
+ core/java/android/app/maintenance/IIdleCallback.aidl \
+ core/java/android/app/maintenance/IIdleService.aidl \
core/java/android/bluetooth/IBluetooth.aidl \
core/java/android/bluetooth/IBluetoothA2dp.aidl \
core/java/android/bluetooth/IBluetoothCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 1ec7f08..c0ed81a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -543,6 +543,7 @@
field public static final int fromAlpha = 16843210; // 0x10101ca
field public static final int fromDegrees = 16843187; // 0x10101b3
field public static final int fromScene = 16843741; // 0x10103dd
+ field public static final int fromSceneName = 16843774; // 0x10103fe
field public static final int fromXDelta = 16843206; // 0x10101c6
field public static final int fromXScale = 16843202; // 0x10101c2
field public static final int fromYDelta = 16843208; // 0x10101c8
@@ -960,6 +961,7 @@
field public static final int shadowRadius = 16843108; // 0x1010164
field public static final int shape = 16843162; // 0x101019a
field public static final int shareInterpolator = 16843195; // 0x10101bb
+ field public static final int sharedElementName = 16843776; // 0x1010400
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
field public static final int shouldDisableView = 16843246; // 0x10101ee
@@ -1142,6 +1144,7 @@
field public static final int toAlpha = 16843211; // 0x10101cb
field public static final int toDegrees = 16843188; // 0x10101b4
field public static final int toScene = 16843742; // 0x10103de
+ field public static final int toSceneName = 16843775; // 0x10103ff
field public static final int toXDelta = 16843207; // 0x10101c7
field public static final int toXScale = 16843203; // 0x10101c3
field public static final int toYDelta = 16843209; // 0x10101c9
@@ -1157,6 +1160,7 @@
field public static final int transformPivotX = 16843552; // 0x1010320
field public static final int transformPivotY = 16843553; // 0x1010321
field public static final int transition = 16843743; // 0x10103df
+ field public static final int transitionGroup = 16843777; // 0x1010401
field public static final int transitionOrdering = 16843744; // 0x10103e0
field public static final int translationX = 16843554; // 0x1010322
field public static final int translationY = 16843555; // 0x1010323
@@ -1514,6 +1518,7 @@
field public static final int selectAll = 16908319; // 0x102001f
field public static final int selectTextMode = 16908333; // 0x102002d
field public static final int selectedIcon = 16908302; // 0x102000e
+ field public static final int shared_element_name = 16908334; // 0x102002e
field public static final int startSelectingText = 16908328; // 0x1020028
field public static final int stopSelectingText = 16908329; // 0x1020029
field public static final int summary = 16908304; // 0x1020010
@@ -3035,6 +3040,7 @@
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
+ method public android.os.Bundle getTransitionArgs();
method public final int getVolumeControlStream();
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
@@ -3130,6 +3136,7 @@
method public void setContentView(android.view.View);
method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public final void setDefaultKeyMode(int);
+ method public void setEarlyBackgroundTransition(boolean);
method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable);
method public final void setFeatureDrawableAlpha(int, int);
method public final void setFeatureDrawableResource(int, int);
@@ -3170,6 +3177,7 @@
method public boolean startNextMatchingActivity(android.content.Intent);
method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+ method protected void startSharedElementTransition(android.os.Bundle);
method public deprecated void stopManagingCursor(android.database.Cursor);
method public void takeKeyEvents(boolean);
method public void triggerSearch(java.lang.String, android.os.Bundle);
@@ -3340,6 +3348,7 @@
public class ActivityOptions {
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
+ method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.os.Bundle);
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
@@ -3349,8 +3358,11 @@
ctor public ActivityView(android.content.Context);
ctor public ActivityView(android.content.Context, android.util.AttributeSet);
ctor public ActivityView(android.content.Context, android.util.AttributeSet, int);
+ method public boolean isAttachedToDisplay();
method protected void onLayout(boolean, int, int, int, int);
method public void startActivity(android.content.Intent);
+ method public void startActivity(android.content.IntentSender);
+ method public void startActivity(android.app.PendingIntent);
}
public class AlarmManager {
@@ -4886,6 +4898,20 @@
}
+package android.app.maintenance {
+
+ public abstract class IdleService extends android.app.Service {
+ ctor public IdleService();
+ method public final void finishIdle();
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract boolean onIdleStart();
+ method public abstract void onIdleStop();
+ field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_IDLE_SERVICE";
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.idle.IdleService";
+ }
+
+}
+
package android.appwidget {
public class AppWidgetHost {
@@ -6187,6 +6213,7 @@
method public abstract android.content.ContentResolver getContentResolver();
method public abstract java.io.File getDatabasePath(java.lang.String);
method public abstract java.io.File getDir(java.lang.String, int);
+ method public final android.graphics.drawable.Drawable getDrawable(int);
method public abstract java.io.File getExternalCacheDir();
method public abstract java.io.File[] getExternalCacheDirs();
method public abstract java.io.File getExternalFilesDir(java.lang.String);
@@ -7998,7 +8025,9 @@
method public int getDimensionPixelSize(int) throws android.content.res.Resources.NotFoundException;
method public android.util.DisplayMetrics getDisplayMetrics();
method public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
+ method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
+ method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
method public float getFraction(int, int, int);
method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;
@@ -8042,6 +8071,7 @@
public final class Resources.Theme {
method public void applyStyle(int, boolean);
method public void dump(int, java.lang.String, java.lang.String);
+ method public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
method public android.content.res.TypedArray obtainStyledAttributes(int[]);
method public android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
method public android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[], int, int);
@@ -10349,6 +10379,7 @@
ctor public BitmapDrawable(android.content.res.Resources, java.lang.String);
ctor public deprecated BitmapDrawable(java.io.InputStream);
ctor public BitmapDrawable(android.content.res.Resources, java.io.InputStream);
+ method public void draw(android.graphics.Canvas);
method public final android.graphics.Bitmap getBitmap();
method public final android.graphics.drawable.Drawable.ConstantState getConstantState();
method public int getGravity();
@@ -10374,6 +10405,7 @@
public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int);
+ method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -10387,6 +10419,7 @@
public class ColorDrawable extends android.graphics.drawable.Drawable {
ctor public ColorDrawable();
ctor public ColorDrawable(int);
+ method public void draw(android.graphics.Canvas);
method public int getColor();
method public int getOpacity();
method public void setAlpha(int);
@@ -10405,7 +10438,7 @@
method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, java.lang.String);
method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.graphics.drawable.Drawable createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public void draw(android.graphics.Canvas);
+ method public abstract void draw(android.graphics.Canvas);
method public int getAlpha();
method public final android.graphics.Rect getBounds();
method public android.graphics.drawable.Drawable.Callback getCallback();
@@ -10429,7 +10462,6 @@
method public void jumpToCurrentState();
method public android.graphics.drawable.Drawable mutate();
method protected void onBoundsChange(android.graphics.Rect);
- method protected void onDraw(android.graphics.Canvas);
method protected boolean onLevelChange(int);
method protected boolean onStateChange(int[]);
method public static int resolveOpacity(int, int);
@@ -10465,6 +10497,7 @@
public class DrawableContainer extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public DrawableContainer();
+ method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -10505,6 +10538,7 @@
public class GradientDrawable extends android.graphics.drawable.Drawable {
ctor public GradientDrawable();
ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
+ method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
method public boolean onStateChange(int[]);
@@ -10551,6 +10585,7 @@
public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
+ method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getDrawable();
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
@@ -10562,6 +10597,7 @@
public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+ method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
method public android.graphics.drawable.Drawable getDrawable(int);
method public int getId(int);
@@ -10592,6 +10628,7 @@
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
+ method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
@@ -10610,6 +10647,7 @@
public class PictureDrawable extends android.graphics.drawable.Drawable {
ctor public PictureDrawable(android.graphics.Picture);
+ method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public android.graphics.Picture getPicture();
method public void setAlpha(int);
@@ -10623,17 +10661,32 @@
public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public RotateDrawable();
+ method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getDrawable();
+ method public float getFromDegrees();
method public int getOpacity();
+ method public float getPivotX();
+ method public float getPivotY();
+ method public float getToDegrees();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
+ method public boolean isPivotXRelative();
+ method public boolean isPivotYRelative();
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setDrawable(android.graphics.drawable.Drawable);
+ method public void setFromDegrees(float);
+ method public void setPivotX(float);
+ method public void setPivotXRelative(boolean);
+ method public void setPivotY(float);
+ method public void setPivotYRelative(boolean);
+ method public void setToDegrees(float);
method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
}
public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float);
+ method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getDrawable();
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
@@ -10646,6 +10699,7 @@
public class ShapeDrawable extends android.graphics.drawable.Drawable {
ctor public ShapeDrawable();
ctor public ShapeDrawable(android.graphics.drawable.shapes.Shape);
+ method public void draw(android.graphics.Canvas);
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public android.graphics.drawable.ShapeDrawable.ShaderFactory getShaderFactory();
@@ -18333,7 +18387,7 @@
public abstract class CountDownTimer {
ctor public CountDownTimer(long, long);
- method public final void cancel();
+ method public final synchronized void cancel();
method public abstract void onFinish();
method public abstract void onTick(long);
method public final synchronized android.os.CountDownTimer start();
@@ -26637,6 +26691,7 @@
method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
method public android.transition.Transition addTarget(int);
method public android.transition.Transition addTarget(android.view.View);
+ method public boolean canRemoveViews();
method public abstract void captureEndValues(android.transition.TransitionValues);
method public abstract void captureStartValues(android.transition.TransitionValues);
method public android.transition.Transition clone();
@@ -28701,6 +28756,7 @@
method public int getScrollBarStyle();
method public final int getScrollX();
method public final int getScrollY();
+ method public java.lang.String getSharedElementName();
method public int getSolidColor();
method protected int getSuggestedMinimumHeight();
method protected int getSuggestedMinimumWidth();
@@ -28954,6 +29010,7 @@
method public void setScrollY(int);
method public void setScrollbarFadingEnabled(boolean);
method public void setSelected(boolean);
+ method public void setSharedElementName(java.lang.String);
method public void setSoundEffectsEnabled(boolean);
method public void setSystemUiVisibility(int);
method public void setTag(java.lang.Object);
@@ -29340,6 +29397,7 @@
method protected boolean isChildrenDrawingOrderEnabled();
method protected boolean isChildrenDrawnWithCacheEnabled();
method public boolean isMotionEventSplittingEnabled();
+ method public boolean isTransitionGroup();
method public final void layout(int, int, int, int);
method protected void measureChild(android.view.View, int, int);
method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -29385,6 +29443,7 @@
method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
method public void setPersistentDrawingCache(int);
method protected void setStaticTransformationsEnabled(boolean);
+ method public void setTransitionGroup(boolean);
method public boolean shouldDelayChildPressedState();
method public boolean showContextMenuForChild(android.view.View);
method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
@@ -29679,7 +29738,6 @@
method public abstract void setTitle(java.lang.CharSequence);
method public abstract deprecated void setTitleColor(int);
method public void setTransitionManager(android.transition.TransitionManager);
- method public void setTransitionOptions(android.os.Bundle);
method public void setType(int);
method public void setUiOptions(int);
method public void setUiOptions(int, int);
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index bfbae24..242b3ea 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -100,7 +100,7 @@
try {
AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
Context authContext = createPackageContext(desc.packageName, 0);
- icon = authContext.getResources().getDrawable(desc.iconId);
+ icon = authContext.getDrawable(desc.iconId);
} catch (PackageManager.NameNotFoundException e) {
// Nothing we can do much here, just log
if (Log.isLoggable(TAG, Log.WARN)) {
diff --git a/core/java/android/accounts/ChooseAccountTypeActivity.java b/core/java/android/accounts/ChooseAccountTypeActivity.java
index acc8549..a3222d8 100644
--- a/core/java/android/accounts/ChooseAccountTypeActivity.java
+++ b/core/java/android/accounts/ChooseAccountTypeActivity.java
@@ -129,7 +129,7 @@
Drawable icon = null;
try {
Context authContext = createPackageContext(desc.packageName, 0);
- icon = authContext.getResources().getDrawable(desc.iconId);
+ icon = authContext.getDrawable(desc.iconId);
final CharSequence sequence = authContext.getResources().getText(desc.labelId);
if (sequence != null) {
name = sequence.toString();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 698f06a..a8716bf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.transition.Scene;
-import android.transition.Transition;
import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.util.SuperNotCalledException;
@@ -771,6 +770,7 @@
private Thread mUiThread;
final Handler mHandler = new Handler();
+ private ActivityOptions mTransitionActivityOptions;
/** Return the intent that started this activity. */
public Intent getIntent() {
@@ -3443,38 +3443,16 @@
*
* @throws android.content.ActivityNotFoundException
*
- * @see #startActivity
+ * @see #startActivity
*/
public void startActivityForResult(Intent intent, int requestCode) {
- final TransitionManager tm = getWindow().getTransitionManager();
- final Scene currScene = getWindow().getContentScene();
- final String[] targetSceneNames = currScene != null && tm != null ?
- tm.getTargetSceneNames(currScene) : null;
-
- if (targetSceneNames == null || targetSceneNames.length == 0) {
- startActivityForResult(intent, requestCode, null);
- } else {
- // TODO Capture the scene transition args and send along
- final ActivityOptions opts = ActivityOptions.makeSceneTransitionAnimation(
- targetSceneNames, null,
- new ActivityOptions.OnSceneTransitionStartedListener() {
- @Override public void onSceneTransitionStarted(String destSceneName) {
- final Transition t = tm.getNamedTransition(currScene, destSceneName);
- // TODO Fill this in to notify the outgoing activity that it should
- // treat this as a sync point for the transition - the target
- // transition has started.
- Log.d(TAG, "Scene transition to scene " + destSceneName +
- " transition " + t);
- }
- }, mHandler);
- startActivityForResult(intent, requestCode, opts.toBundle());
- }
+ startActivityForResult(intent, requestCode, null);
}
/**
* Launch an activity for which you would like a result when it finished.
* When this activity exits, your
- * onActivityResult() method will be called with the given requestCode.
+ * onActivityResult() method will be called with the given requestCode.
* Using a negative requestCode is the same as calling
* {@link #startActivity} (the activity is not launched as a sub-activity).
*
@@ -3487,9 +3465,9 @@
*
* <p>As a special case, if you call startActivityForResult() with a requestCode
* >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
- * activity, then your window will not be displayed until a result is
- * returned back from the started activity. This is to avoid visible
- * flickering when redirecting to another activity.
+ * activity, then your window will not be displayed until a result is
+ * returned back from the started activity. This is to avoid visible
+ * flickering when redirecting to another activity.
*
* <p>This method throws {@link android.content.ActivityNotFoundException}
* if there was no Activity found to run the given Intent.
@@ -3503,9 +3481,17 @@
*
* @throws android.content.ActivityNotFoundException
*
- * @see #startActivity
+ * @see #startActivity
*/
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
+ TransitionManager tm = getContentTransitionManager();
+ if (tm != null && options != null) {
+ ActivityOptions activityOptions = new ActivityOptions(options);
+ if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ getWindow().startExitTransition(activityOptions);
+ options = activityOptions.toBundle();
+ }
+ }
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
@@ -5313,7 +5299,7 @@
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
-
+
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
@@ -5335,8 +5321,40 @@
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
- mWindow.setTransitionOptions(options);
mCurrentConfig = config;
+ mTransitionActivityOptions = null;
+ Window.SceneTransitionListener sceneTransitionListener = null;
+ if (options != null) {
+ ActivityOptions activityOptions = new ActivityOptions(options);
+ if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ mTransitionActivityOptions = activityOptions;
+ sceneTransitionListener = new Window.SceneTransitionListener() {
+ @Override
+ public void enterSharedElement(Bundle transitionArgs) {
+ startSharedElementTransition(transitionArgs);
+ mTransitionActivityOptions = null;
+ }
+
+ @Override
+ public void nullPendingTransition() {
+ overridePendingTransition(0, 0);
+ }
+
+ @Override
+ public void convertFromTranslucent() {
+ Activity.this.convertFromTranslucent();
+ }
+
+ @Override
+ public void convertToTranslucent() {
+ Activity.this.convertToTranslucent(null);
+ }
+ };
+
+ }
+ }
+
+ mWindow.setTransitionOptions(mTransitionActivityOptions, sceneTransitionListener);
}
/** @hide */
@@ -5350,7 +5368,7 @@
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
}
-
+
final void performStart() {
mFragments.noteStateNotSaved();
mCalled = false;
@@ -5507,7 +5525,7 @@
}
}
}
-
+
mStopped = true;
}
mResumed = false;
@@ -5522,7 +5540,57 @@
mLoaderManager.doDestroy();
}
}
-
+
+ /**
+ * Gets the entering Activity transition args. Will be null if
+ * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)} was
+ * not used to pass a Bundle to startActivity. The Bundle passed to that method in the
+ * calling Activity is returned here.
+ * <p>After startSharedElementTransition is called, this method will return null.</p>
+ *
+ * @return The Bundle passed into Bundle parameter of
+ * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)}
+ * in the calling Activity.
+ */
+ public Bundle getTransitionArgs() {
+ if (mTransitionActivityOptions == null) {
+ return null;
+ }
+ return mTransitionActivityOptions.getSceneTransitionArgs();
+ }
+
+ /**
+ * Override to transfer a shared element from a calling Activity to this Activity.
+ * Shared elements will be made VISIBLE before this call. The Activity is responsible
+ * for transitioning the shared elements from their location to the eventual destination.
+ * The shared element will be laid out a the destination when this method is called.
+ *
+ * @param transitionArgs The same as returned from {@link #getTransitionArgs()}, this should
+ * contain information from the calling Activity to tell where the
+ * shared element should be placed.
+ */
+ protected void startSharedElementTransition(Bundle transitionArgs) {
+ }
+
+ /**
+ * Controls how the background fade is triggered when there is an entering Activity transition.
+ * If fadeEarly is true, the Window background will fade in as soon as the shared elements are
+ * ready to switch. If fadeEarly is false, the background will fade only after the calling
+ * Activity's exit transition completes. By default, the Window will fade in when the calling
+ * Activity's exit transition completes.
+ *
+ * @param fadeEarly Set to true to fade out the exiting Activity as soon as the shared elements
+ * are transferred. Set to false to fade out the exiting Activity as soon as
+ * the shared element is transferred.
+ * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+ */
+ public void setEarlyBackgroundTransition(boolean fadeEarly) {
+ if (mTransitionActivityOptions == null) {
+ return;
+ }
+ mWindow.setEarlyBackgroundTransition(fadeEarly);
+ }
+
/**
* @hide
*/
@@ -5530,7 +5598,7 @@
return mResumed;
}
- void dispatchActivityResult(String who, int requestCode,
+ void dispatchActivityResult(String who, int requestCode,
int resultCode, Intent data) {
if (false) Log.v(
TAG, "Dispatching result: who=" + who + ", reqCode=" + requestCode
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 582ce3c..3f97c40 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -16,16 +16,21 @@
package android.app;
+import android.animation.Animator;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
-import android.text.TextUtils;
+import android.transition.Transition;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
+import java.util.ArrayList;
+import java.util.Map;
+
/**
* Helper class for building an options Bundle that can be used with
* {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
@@ -95,34 +100,30 @@
public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
/**
- * A string array of names for the destination scene. This defines an API in the same
- * way that intent action or extra names do and should follow a similar convention:
- * "com.example.scene.FOO"
- *
- * @hide
- */
- public static final String KEY_DEST_SCENE_NAMES = "android:destSceneNames";
-
- /**
- * A string indicating the destination scene name that was chosen by the target.
- * Used by {@link OnSceneTransitionStartedListener}.
- * @hide
- */
- public static final String KEY_DEST_SCENE_NAME_CHOSEN = "android:destSceneNameChosen";
-
- /**
- * Callback for when scene transition is started.
- * @hide
- */
- public static final String KEY_SCENE_TRANSITION_START_LISTENER =
- "android:sceneTransitionStartListener";
-
- /**
* Arguments for the scene transition about to begin.
* @hide
*/
public static final String KEY_SCENE_TRANSITION_ARGS = "android:sceneTransitionArgs";
+ /**
+ * For Activity transitions, the calling Activity's TransitionListener used to
+ * notify the called Activity when the shared element and the exit transitions
+ * complete.
+ */
+ private static final String KEY_TRANSITION_COMPLETE_LISTENER
+ = "android:transitionCompleteListener";
+
+ /**
+ * For Activity transitions, the called Activity's listener to receive calls
+ * when transitions complete.
+ */
+ private static final String KEY_TRANSITION_TARGET_LISTENER = "android:transitionTargetListener";
+
+ /**
+ * The shared element's texture ID (TODO: not used yet).
+ */
+ private static final String KEY_SHARED_ELEMENT_TEXTURE_ID = "android:sharedElementTextureId";
+
/** @hide */
public static final int ANIM_NONE = 0;
/** @hide */
@@ -145,10 +146,9 @@
private int mStartY;
private int mStartWidth;
private int mStartHeight;
- private String[] mDestSceneNames;
private Bundle mTransitionArgs;
private IRemoteCallback mAnimationStartedListener;
- private IRemoteCallback mSceneTransitionStartedListener;
+ private IRemoteCallback mTransitionCompleteListener;
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -215,24 +215,6 @@
}
}
- private void setOnSceneTransitionStartedListener(Handler handler,
- OnSceneTransitionStartedListener listener) {
- if (listener != null) {
- final Handler h = handler;
- final OnSceneTransitionStartedListener l = listener;
- mSceneTransitionStartedListener = new IRemoteCallback.Stub() {
- @Override public void sendResult(final Bundle data) throws RemoteException {
- h.post(new Runnable() {
- public void run() {
- l.onSceneTransitionStarted(data != null ?
- data.getString(KEY_DEST_SCENE_NAME_CHOSEN) : null);
- }
- });
- }
- };
- }
- }
-
/**
* Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
* to find out when the given animation has started running.
@@ -242,13 +224,10 @@
void onAnimationStarted();
}
- /**
- * Callback for use with {@link ActivityOptions#makeSceneTransitionAnimation}
- * to find out when a transition is about to begin.
- * @hide
- */
- public interface OnSceneTransitionStartedListener {
- void onSceneTransitionStarted(String destSceneName);
+ /** @hide */
+ public interface ActivityTransitionTarget {
+ void sharedElementTransitionComplete();
+ void exitTransitionComplete();
}
/**
@@ -369,18 +348,35 @@
}
/**
- * Create an ActivityOptions specifying an animation where an activity window is asked
- * to perform animations within the window content.
+ * Create an ActivityOptions to transition between Activities using cross-Activity animation.
+ * When visual elements are to carry between Activities, args should be used to tell the called
+ * Activity about the location and size.
*
- * @hide
+ * TODO: Provide facility to capture layout and bitmap of shared elements.
+ *
+ * <p>When
+ * {@link android.app.Activity#startActivities(android.content.Intent[], android.os.Bundle)}
+ * is used with the {@link #toBundle()} result, the Activity's content scene will automatically
+ * transition out by setting their visibility to {@link View#INVISIBLE}. Shared elements
+ * ({@link android.view.View#setSharedElementName(String)}) are unmodified during the
+ * transition to allow the started Activity to seamlessly take it over. ViewGroups typically
+ * don't transition out, and instead transition out their children unless they have a
+ * background. To modify this behavior, use
+ * {@link android.view.ViewGroup#setTransitionGroup(boolean)}.</p>
+ *
+ * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
+ * enabled on the calling Activity to cause an exit transition. The same must be in
+ * the called Activity to get an entering transition.</p>
+ *
+ * @param args Contains information for transferring a view between this Activity and the
+ * target Activity. Will be used by the called Activity to transition the
+ * view to its eventual destination
+ * @see android.app.Activity#startSharedElementTransition(android.os.Bundle)
*/
- public static ActivityOptions makeSceneTransitionAnimation(String[] destSceneNames,
- Bundle args, OnSceneTransitionStartedListener listener, Handler handler) {
+ public static ActivityOptions makeSceneTransitionAnimation(Bundle args) {
ActivityOptions opts = new ActivityOptions();
opts.mAnimationType = ANIM_SCENE_TRANSITION;
- opts.mDestSceneNames = destSceneNames;
opts.mTransitionArgs = args;
- opts.setOnSceneTransitionStartedListener(handler, listener);
return opts;
}
@@ -416,10 +412,9 @@
break;
case ANIM_SCENE_TRANSITION:
- mDestSceneNames = opts.getStringArray(KEY_DEST_SCENE_NAMES);
mTransitionArgs = opts.getBundle(KEY_SCENE_TRANSITION_ARGS);
- mSceneTransitionStartedListener = IRemoteCallback.Stub.asInterface(
- opts.getBinder(KEY_SCENE_TRANSITION_START_LISTENER));
+ mTransitionCompleteListener = IRemoteCallback.Stub.asInterface(
+ opts.getBinder(KEY_TRANSITION_COMPLETE_LISTENER));
break;
}
}
@@ -470,11 +465,6 @@
}
/** @hide */
- public String[] getDestSceneNames() {
- return mDestSceneNames;
- }
-
- /** @hide */
public Bundle getSceneTransitionArgs() {
return mTransitionArgs;
}
@@ -485,19 +475,33 @@
}
/** @hide */
- public void dispatchSceneTransitionStarted(String destScene) {
- if (mSceneTransitionStartedListener != null) {
- Bundle data = null;
- if (!TextUtils.isEmpty(destScene)) {
- data = new Bundle();
- data.putString(KEY_DEST_SCENE_NAME_CHOSEN, destScene);
- }
+ public void dispatchSceneTransitionStarted(final ActivityTransitionTarget target) {
+ boolean listenerSent = false;
+ if (mTransitionCompleteListener != null) {
+ IRemoteCallback callback = new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ if (data == null) {
+ target.exitTransitionComplete();
+ } else {
+ // TODO: Use texture id
+ target.sharedElementTransitionComplete();
+ }
+ }
+ };
+ Bundle bundle = new Bundle();
+ bundle.putBinder(KEY_TRANSITION_TARGET_LISTENER, callback.asBinder());
try {
- mSceneTransitionStartedListener.sendResult(data);
+ mTransitionCompleteListener.sendResult(bundle);
+ listenerSent = true;
} catch (RemoteException e) {
- Log.e(TAG, "Caught exception dispatching scene transition start", e);
+ Log.w(TAG, "Couldn't retrieve transition notifications", e);
}
}
+ if (!listenerSent) {
+ target.sharedElementTransitionComplete();
+ target.exitTransitionComplete();
+ }
}
/** @hide */
@@ -508,12 +512,6 @@
} catch (RemoteException e) {
}
}
- if (mSceneTransitionStartedListener != null) {
- try {
- mSceneTransitionStartedListener.sendResult(null);
- } catch (RemoteException e) {
- }
- }
}
/** @hide */
@@ -545,9 +543,8 @@
}
}
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
- mSceneTransitionStartedListener = null;
+ mTransitionCompleteListener = null;
mTransitionArgs = null;
- mDestSceneNames = null;
break;
case ANIM_SCALE_UP:
mAnimationType = otherOptions.mAnimationType;
@@ -562,9 +559,8 @@
}
}
mAnimationStartedListener = null;
- mSceneTransitionStartedListener = null;
+ mTransitionCompleteListener = null;
mTransitionArgs = null;
- mDestSceneNames = null;
break;
case ANIM_THUMBNAIL_SCALE_UP:
case ANIM_THUMBNAIL_SCALE_DOWN:
@@ -579,20 +575,12 @@
}
}
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
- mSceneTransitionStartedListener = null;
+ mTransitionCompleteListener = null;
mTransitionArgs = null;
- mDestSceneNames = null;
break;
case ANIM_SCENE_TRANSITION:
mAnimationType = otherOptions.mAnimationType;
- if (mSceneTransitionStartedListener != null) {
- try {
- mSceneTransitionStartedListener.sendResult(null);
- } catch (RemoteException e) {
- }
- }
- mSceneTransitionStartedListener = otherOptions.mSceneTransitionStartedListener;
- mDestSceneNames = otherOptions.mDestSceneNames;
+ mTransitionCompleteListener = otherOptions.mTransitionCompleteListener;
mTransitionArgs = otherOptions.mTransitionArgs;
mThumbnail = null;
mAnimationStartedListener = null;
@@ -639,10 +627,11 @@
break;
case ANIM_SCENE_TRANSITION:
b.putInt(KEY_ANIM_TYPE, mAnimationType);
- b.putStringArray(KEY_DEST_SCENE_NAMES, mDestSceneNames);
b.putBundle(KEY_SCENE_TRANSITION_ARGS, mTransitionArgs);
- b.putBinder(KEY_SCENE_TRANSITION_START_LISTENER, mSceneTransitionStartedListener
- != null ? mSceneTransitionStartedListener.asBinder() : null);
+ if (mTransitionCompleteListener != null) {
+ b.putBinder(KEY_TRANSITION_COMPLETE_LISTENER,
+ mTransitionCompleteListener.asBinder());
+ }
break;
}
return b;
@@ -661,4 +650,123 @@
return null;
}
+
+ /** @hide */
+ public interface SharedElementSource {
+ int getTextureId();
+ }
+
+ /**
+ * In the calling Activity when transitioning out, sets the Transition to listen for
+ * changes.
+ * @hide
+ */
+ public void setExitTransition(Transition transition, SharedElementSource sharedElementSource) {
+ mTransitionCompleteListener = new ExitTransitionListener(transition, sharedElementSource);
+ }
+
+ private static class ExitTransitionListener extends IRemoteCallback.Stub
+ implements Transition.TransitionListener, Animator.AnimatorListener {
+ private ArrayList<Animator> mSharedElementAnimators = new ArrayList<Animator>();
+ private boolean mSharedElementNotified;
+ private Transition mExitTransition;
+ private IRemoteCallback mTransitionCompleteCallback;
+ private boolean mExitComplete;
+ private SharedElementSource mSharedElementSource;
+
+ public ExitTransitionListener(Transition transition, SharedElementSource sharedElementSource) {
+ mSharedElementSource = sharedElementSource;
+ mExitTransition = transition;
+ mExitTransition.addListener(this);
+ }
+
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ if (data != null) {
+ mTransitionCompleteCallback = IRemoteCallback.Stub.asInterface(
+ data.getBinder(KEY_TRANSITION_TARGET_LISTENER));
+ notifySharedElement();
+ notifyExit();
+ }
+ }
+
+ @Override
+ public void onTransitionStart(Transition transition) {
+ ArrayMap<Animator, Transition.AnimationInfo> runningAnimators
+ = Transition.getRunningAnimators();
+ for (Map.Entry<Animator, Transition.AnimationInfo> entry : runningAnimators.entrySet()) {
+ if (entry.getValue().view.getSharedElementName() != null) {
+ mSharedElementAnimators.add(entry.getKey());
+ entry.getKey().addListener(this);
+ }
+ }
+ notifySharedElement();
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ mExitComplete = true;
+ notifyExit();
+ mExitTransition.removeListener(this);
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ mExitComplete = true;
+ notifyExit();
+ mExitTransition.removeListener(this);
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSharedElementAnimators.remove(animation);
+ notifySharedElement();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mSharedElementAnimators.remove(animation);
+ notifySharedElement();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ private void notifySharedElement() {
+ if (!mSharedElementNotified && mSharedElementAnimators.isEmpty()
+ && mTransitionCompleteCallback != null) {
+ mSharedElementNotified = true;
+ try {
+ Bundle bundle = new Bundle();
+ bundle.putInt(KEY_SHARED_ELEMENT_TEXTURE_ID, mSharedElementSource.getTextureId());
+ mTransitionCompleteCallback.sendResult(bundle);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Couldn't notify that the transition ended", e);
+ }
+ }
+ }
+
+ private void notifyExit() {
+ if (mExitComplete && mTransitionCompleteCallback != null) {
+ try {
+ mTransitionCompleteCallback.sendResult(null);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Couldn't notify that the transition ended", e);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 25cde8c..df4ec78 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.IntentSender;
import android.graphics.SurfaceTexture;
import android.os.IBinder;
import android.os.RemoteException;
@@ -28,6 +29,7 @@
import android.view.Surface;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -37,7 +39,6 @@
private final TextureView mTextureView;
private IActivityContainer mActivityContainer;
private Activity mActivity;
- private boolean mAttached;
private int mWidth;
private int mHeight;
private Surface mSurface;
@@ -85,24 +86,33 @@
+ e);
}
- final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
- if (surfaceTexture != null) {
- attachToSurface(surfaceTexture);
- }
+ attachToSurfaceWhenReady();
}
@Override
protected void onDetachedFromWindow() {
- detachFromSurface();
+ if (mActivityContainer != null) {
+ detach();
+ mActivityContainer = null;
+ }
}
@Override
- public boolean isAttachedToWindow() {
- return mAttached;
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility == View.VISIBLE) {
+ attachToSurfaceWhenReady();
+ } else {
+ detach();
+ }
+ }
+
+ public boolean isAttachedToDisplay() {
+ return mSurface != null;
}
public void startActivity(Intent intent) {
- if (mActivityContainer != null && mAttached) {
+ if (mSurface != null) {
try {
mActivityContainer.startActivity(intent);
} catch (RemoteException e) {
@@ -111,40 +121,59 @@
}
}
- /** Call when both mActivityContainer and mTextureView's SurfaceTexture are not null */
- private void attachToSurface(SurfaceTexture surfaceTexture) {
+ public void startActivity(IntentSender intentSender) {
+ if (mSurface != null) {
+ try {
+ mActivityContainer.startActivityIntentSender(intentSender.getTarget());
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "ActivityView: Unable to startActivity from IntentSender. " + e);
+ }
+ }
+ }
+
+ public void startActivity(PendingIntent pendingIntent) {
+ if (mSurface != null) {
+ try {
+ mActivityContainer.startActivityIntentSender(pendingIntent.getTarget());
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "ActivityView: Unable to startActivity from PendingIntent. " + e);
+ }
+ }
+ }
+
+ private void attachToSurfaceWhenReady() {
+ final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
+ if (mActivityContainer == null || surfaceTexture == null || mSurface != null) {
+ // Either not ready to attach, or already attached.
+ return;
+ }
+
WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
mSurface = new Surface(surfaceTexture);
try {
- mActivityContainer.attachToSurface(mSurface, mWidth, mHeight,
- metrics.densityDpi);
+ mActivityContainer.attachToSurface(mSurface, mWidth, mHeight, metrics.densityDpi);
} catch (RemoteException e) {
- mActivityContainer = null;
mSurface.release();
mSurface = null;
- mAttached = false;
throw new IllegalStateException(
"ActivityView: Unable to create ActivityContainer. " + e);
}
- mAttached = true;
}
- private void detachFromSurface() {
- if (mActivityContainer != null) {
+ private void detach() {
+ if (mSurface != null) {
try {
mActivityContainer.detachFromDisplay();
} catch (RemoteException e) {
}
- mActivityContainer = null;
- }
- if (mSurface != null) {
mSurface.release();
mSurface = null;
}
- mAttached = false;
}
private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
@@ -154,7 +183,7 @@
mWidth = width;
mHeight = height;
if (mActivityContainer != null) {
- attachToSurface(surfaceTexture);
+ attachToSurfaceWhenReady();
}
}
@@ -167,7 +196,7 @@
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
Log.d(TAG, "onSurfaceTextureDestroyed");
- detachFromSurface();
+ detach();
return true;
}
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index df1cf91..abd296a 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -18,6 +18,7 @@
import android.app.IActivityContainerCallback;
import android.content.Intent;
+import android.content.IIntentSender;
import android.os.IBinder;
import android.view.Surface;
@@ -27,5 +28,6 @@
void attachToSurface(in Surface surface, int width, int height, int density);
void detachFromDisplay();
int startActivity(in Intent intent);
+ int startActivityIntentSender(in IIntentSender intentSender);
int getDisplayId();
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index d04e9db..af1810b 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -188,8 +188,7 @@
mSearchView.findViewById(com.android.internal.R.id.search_src_text);
mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon);
mSearchPlate = mSearchView.findViewById(com.android.internal.R.id.search_plate);
- mWorkingSpinner = getContext().getResources().
- getDrawable(com.android.internal.R.drawable.search_spinner);
+ mWorkingSpinner = getContext().getDrawable(com.android.internal.R.drawable.search_spinner);
// TODO: Restore the spinner for slow suggestion lookups
// mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
// null, null, mWorkingSpinner, null);
@@ -458,7 +457,7 @@
// optionally show one or the other.
if (mSearchable.useBadgeIcon()) {
- icon = mActivityContext.getResources().getDrawable(mSearchable.getIconId());
+ icon = mActivityContext.getDrawable(mSearchable.getIconId());
visibility = View.VISIBLE;
if (DBG) Log.d(LOG_TAG, "Using badge icon: " + mSearchable.getIconId());
} else if (mSearchable.useBadgeLabel()) {
diff --git a/core/java/android/app/maintenance/IIdleCallback.aidl b/core/java/android/app/maintenance/IIdleCallback.aidl
new file mode 100644
index 0000000..582dede
--- /dev/null
+++ b/core/java/android/app/maintenance/IIdleCallback.aidl
@@ -0,0 +1,53 @@
+/**
+ * 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.app.maintenance;
+
+import android.app.maintenance.IIdleService;
+
+/**
+ * The server side of the idle maintenance IPC protocols. The app-side implementation
+ * invokes on this interface to indicate completion of the (asynchronous) instructions
+ * issued by the server.
+ *
+ * In all cases, the 'who' parameter is the caller's service binder, used to track
+ * which idle service instance is reporting.
+ *
+ * {@hide}
+ */
+interface IIdleCallback {
+ /**
+ * Acknowledge receipt and processing of the asynchronous "start idle work" incall.
+ * 'result' is true if the app wants some time to perform ongoing background
+ * idle-time work; or false if the app declares that it does not need any time
+ * for such work.
+ */
+ void acknowledgeStart(int token, boolean result);
+
+ /**
+ * Acknowledge receipt and processing of the asynchronous "stop idle work" incall.
+ */
+ void acknowledgeStop(int token);
+
+ /*
+ * Tell the idle service manager that we're done with our idle maintenance, so that
+ * it can go on to the next one and stop attributing wakelock time to us etc.
+ *
+ * @param opToken The identifier passed in the startIdleMaintenance() call that
+ * indicated the beginning of this service's idle timeslice.
+ */
+ void idleFinished(int token);
+}
diff --git a/core/java/android/app/maintenance/IIdleService.aidl b/core/java/android/app/maintenance/IIdleService.aidl
new file mode 100644
index 0000000..54abccd
--- /dev/null
+++ b/core/java/android/app/maintenance/IIdleService.aidl
@@ -0,0 +1,34 @@
+/**
+ * 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.app.maintenance;
+
+import android.app.maintenance.IIdleCallback;
+
+/**
+ * Interface that the framework uses to communicate with application code
+ * that implements an idle-time "maintenance" service. End user code does
+ * not implement this interface directly; instead, the app's idle service
+ * implementation will extend android.app.maintenance.IdleService.
+ * {@hide}
+ */
+oneway interface IIdleService {
+ /**
+ * Begin your idle-time work.
+ */
+ void startIdleMaintenance(IIdleCallback callbackBinder, int token);
+ void stopIdleMaintenance(IIdleCallback callbackBinder, int token);
+}
diff --git a/core/java/android/app/maintenance/IdleService.java b/core/java/android/app/maintenance/IdleService.java
new file mode 100644
index 0000000..2331b81
--- /dev/null
+++ b/core/java/android/app/maintenance/IdleService.java
@@ -0,0 +1,228 @@
+/*
+ * 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.maintenance;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Intent;
+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.Slog;
+
+/**
+ * Idle maintenance API. Full docs TBW (to be written).
+ */
+public abstract class IdleService extends Service {
+ private static final String TAG = "IdleService";
+
+ static final int MSG_START = 1;
+ static final int MSG_STOP = 2;
+ static final int MSG_FINISH = 3;
+
+ IdleHandler mHandler;
+ IIdleCallback mCallbackBinder;
+ int mToken;
+ final Object mHandlerLock = new Object();
+
+ void ensureHandler() {
+ synchronized (mHandlerLock) {
+ if (mHandler == null) {
+ mHandler = new IdleHandler(getMainLooper());
+ }
+ }
+ }
+
+ /**
+ * TBW: the idle service should supply an intent-filter handling this intent
+ * <p>
+ * <p class="note">The application must also protect the idle service with the
+ * {@code "android.permission.BIND_IDLE_SERVICE"} permission to ensure that other
+ * applications cannot maliciously bind to it. If an idle service's manifest
+ * declaration does not require that permission, it will never be invoked.
+ * </p>
+ */
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "android.service.idle.IdleService";
+
+ /**
+ * Idle services must be protected with this permission:
+ *
+ * <pre class="prettyprint">
+ * <service android:name="MyIdleService"
+ * android:permission="android.permission.BIND_IDLE_SERVICE" >
+ * ...
+ * </service>
+ * </pre>
+ *
+ * <p>If an idle service is declared in the manifest but not protected with this
+ * permission, that service will be ignored by the OS.
+ */
+ public static final String PERMISSION_BIND =
+ "android.permission.BIND_IDLE_SERVICE";
+
+ // Trampoline: the callbacks are always run on the main thread
+ IIdleService mBinder = new IIdleService.Stub() {
+ @Override
+ public void startIdleMaintenance(IIdleCallback callbackBinder, int token)
+ throws RemoteException {
+ ensureHandler();
+ Message msg = mHandler.obtainMessage(MSG_START, token, 0, callbackBinder);
+ mHandler.sendMessage(msg);
+ }
+
+ @Override
+ public void stopIdleMaintenance(IIdleCallback callbackBinder, int token)
+ throws RemoteException {
+ ensureHandler();
+ Message msg = mHandler.obtainMessage(MSG_STOP, token, 0, callbackBinder);
+ mHandler.sendMessage(msg);
+ }
+ };
+
+ /**
+ * Your application may begin doing "idle" maintenance work in the background.
+ * <p>
+ * Your application may continue to run in the background until it receives a call
+ * to {@link #onIdleStop()}, at which point you <i>must</i> cease doing work. The
+ * OS will hold a wakelock on your application's behalf from the time this method is
+ * called until after the following call to {@link #onIdleStop()} returns.
+ * </p>
+ * <p>
+ * Returning {@code false} from this method indicates that you have no ongoing work
+ * to do at present. The OS will respond by immediately calling {@link #onIdleStop()}
+ * and returning your application to its normal stopped state. Returning {@code true}
+ * indicates that the application is indeed performing ongoing work, so the OS will
+ * let your application run in this state until it's no longer appropriate.
+ * </p>
+ * <p>
+ * You will always receive a matching call to {@link #onIdleStop()} even if your
+ * application returns {@code false} from this method.
+ *
+ * @return {@code true} to indicate that the application wishes to perform some ongoing
+ * background work; {@code false} to indicate that it does not need to perform such
+ * work at present.
+ */
+ public abstract boolean onIdleStart();
+
+ /**
+ * Your app's maintenance opportunity is over. Once the application returns from
+ * this method, the wakelock held by the OS on its behalf will be released.
+ */
+ public abstract void onIdleStop();
+
+ /**
+ * Tell the OS that you have finished your idle work. Calling this more than once,
+ * or calling it when you have not received an {@link #onIdleStart()} callback, is
+ * an error.
+ *
+ * <p>It is safe to call {@link #finishIdle()} from any thread.
+ */
+ public final void finishIdle() {
+ ensureHandler();
+ mHandler.sendEmptyMessage(MSG_FINISH);
+ }
+
+ class IdleHandler extends Handler {
+ IdleHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_START: {
+ // Call the concrete onIdleStart(), reporting its return value back to
+ // the OS. If onIdleStart() throws, report it as a 'false' return but
+ // rethrow the exception at the offending app.
+ boolean result = false;
+ IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
+ mCallbackBinder = callbackBinder;
+ final int token = mToken = msg.arg1;
+ try {
+ result = IdleService.this.onIdleStart();
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to start idle workload", e);
+ throw new RuntimeException(e);
+ } finally {
+ // don't bother if the service already called finishIdle()
+ if (mCallbackBinder != null) {
+ try {
+ callbackBinder.acknowledgeStart(token, result);
+ } catch (RemoteException re) {
+ Log.e(TAG, "System unreachable to start idle workload");
+ }
+ }
+ }
+ break;
+ }
+
+ case MSG_STOP: {
+ // Structured just like MSG_START for the stop-idle bookend call.
+ IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
+ final int token = msg.arg1;
+ try {
+ IdleService.this.onIdleStop();
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to stop idle workload", e);
+ throw new RuntimeException(e);
+ } finally {
+ if (mCallbackBinder != null) {
+ try {
+ callbackBinder.acknowledgeStop(token);
+ } catch (RemoteException re) {
+ Log.e(TAG, "System unreachable to stop idle workload");
+ }
+ }
+ }
+ break;
+ }
+
+ case MSG_FINISH: {
+ if (mCallbackBinder != null) {
+ try {
+ mCallbackBinder.idleFinished(mToken);
+ } catch (RemoteException e) {
+ Log.e(TAG, "System unreachable to finish idling");
+ } finally {
+ mCallbackBinder = null;
+ }
+ } else {
+ Log.e(TAG, "finishIdle() called but the idle service is not started");
+ }
+ break;
+ }
+
+ default: {
+ Slog.w(TAG, "Unknown message " + msg.what);
+ }
+ }
+ }
+ }
+
+ /** @hide */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return mBinder.asBinder();
+ }
+
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ac08d9b..9f90de0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -376,6 +376,19 @@
return getResources().getString(resId, formatArgs);
}
+ /**
+ * Return a drawable object associated with a particular resource ID and
+ * styled for the current theme.
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ * @return Drawable An object that can be used to draw this resource.
+ */
+ public final Drawable getDrawable(int id) {
+ return getResources().getDrawable(id, getTheme());
+ }
+
/**
* Set the base theme for this context. Note that this should be called
* before any views are instantiated in the Context (for example before
diff --git a/core/java/android/content/SyncActivityTooManyDeletes.java b/core/java/android/content/SyncActivityTooManyDeletes.java
index 350f35e..093fb08 100644
--- a/core/java/android/content/SyncActivityTooManyDeletes.java
+++ b/core/java/android/content/SyncActivityTooManyDeletes.java
@@ -95,7 +95,7 @@
// try {
// final Context authContext = createPackageContext(desc.packageName, 0);
// ImageView imageView = new ImageView(this);
-// imageView.setImageDrawable(authContext.getResources().getDrawable(desc.iconId));
+// imageView.setImageDrawable(authContext.getDrawable(desc.iconId));
// ll.addView(imageView, lp);
// } catch (PackageManager.NameNotFoundException e) {
// }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index b0b8d2d..aa96f0e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -94,12 +94,13 @@
private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists
= new LongSparseArray<ColorStateList>();
- private static Resources mSystem = null;
+ // Used by BridgeResources in layoutlib
+ static Resources mSystem = null;
+
private static boolean sPreloaded;
private static int sPreloadedDensity;
// These are protected by mAccessLock.
-
private final Object mAccessLock = new Object();
private final Configuration mTmpConfig = new Configuration();
private final LongSparseArray<WeakReference<Drawable.ConstantState>> mDrawableCache
@@ -685,12 +686,27 @@
* @param id The desired resource identifier, as generated by the aapt
* tool. This integer encodes the package, type, and resource
* entry. The value 0 is an invalid identifier.
- *
- * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
- *
* @return Drawable An object that can be used to draw this resource.
+ * @throws NotFoundException Throws NotFoundException if the given ID does
+ * not exist.
*/
public Drawable getDrawable(int id) throws NotFoundException {
+ return getDrawable(id, null);
+ }
+
+ /**
+ * Return a drawable object associated with a particular resource ID and
+ * styled for the specified theme.
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ * @param theme The theme used to style the drawable attributes.
+ * @return Drawable An object that can be used to draw this resource.
+ * @throws NotFoundException Throws NotFoundException if the given ID does
+ * not exist.
+ */
+ public Drawable getDrawable(int id, Theme theme) throws NotFoundException {
TypedValue value;
synchronized (mAccessLock) {
value = mTmpValue;
@@ -701,7 +717,7 @@
}
getValue(id, value, true);
}
- Drawable res = loadDrawable(value, id);
+ final Drawable res = loadDrawable(value, id, theme);
synchronized (mAccessLock) {
if (mTmpValue == null) {
mTmpValue = value;
@@ -719,17 +735,36 @@
* depending on the underlying resource -- for example, a solid color, PNG
* image, scalable image, etc. The Drawable API hides these implementation
* details.
- *
+ *
* @param id The desired resource identifier, as generated by the aapt tool.
* This integer encodes the package, type, and resource entry.
* The value 0 is an invalid identifier.
* @param density the desired screen density indicated by the resource as
* found in {@link DisplayMetrics}.
+ * @return Drawable An object that can be used to draw this resource.
* @throws NotFoundException Throws NotFoundException if the given ID does
* not exist.
- * @return Drawable An object that can be used to draw this resource.
+ * @see #getDrawableForDensity(int, int, Theme)
*/
public Drawable getDrawableForDensity(int id, int density) throws NotFoundException {
+ return getDrawableForDensity(id, density, null);
+ }
+
+ /**
+ * Return a drawable object associated with a particular resource ID for the
+ * given screen density in DPI and styled for the specified theme.
+ *
+ * @param id The desired resource identifier, as generated by the aapt tool.
+ * This integer encodes the package, type, and resource entry.
+ * The value 0 is an invalid identifier.
+ * @param density The desired screen density indicated by the resource as
+ * found in {@link DisplayMetrics}.
+ * @param theme The theme used to style the drawable attributes.
+ * @return Drawable An object that can be used to draw this resource.
+ * @throws NotFoundException Throws NotFoundException if the given ID does
+ * not exist.
+ */
+ public Drawable getDrawableForDensity(int id, int density, Theme theme) {
TypedValue value;
synchronized (mAccessLock) {
value = mTmpValue;
@@ -756,7 +791,7 @@
}
}
- Drawable res = loadDrawable(value, id);
+ final Drawable res = loadDrawable(value, id, theme);
synchronized (mAccessLock) {
if (mTmpValue == null) {
mTmpValue = value;
@@ -1250,8 +1285,9 @@
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
public TypedArray obtainStyledAttributes(int[] attrs) {
- int len = attrs.length;
- TypedArray array = getCachedStyledAttributes(len);
+ final int len = attrs.length;
+ final TypedArray array = getCachedStyledAttributes(len);
+ array.mTheme = this;
array.mRsrcs = attrs;
AssetManager.applyStyle(mTheme, 0, 0, 0, attrs,
array.mData, array.mIndices);
@@ -1278,10 +1314,10 @@
* @see #obtainStyledAttributes(int[])
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
- public TypedArray obtainStyledAttributes(int resid, int[] attrs)
- throws NotFoundException {
- int len = attrs.length;
- TypedArray array = getCachedStyledAttributes(len);
+ public TypedArray obtainStyledAttributes(int resid, int[] attrs) throws NotFoundException {
+ final int len = attrs.length;
+ final TypedArray array = getCachedStyledAttributes(len);
+ array.mTheme = this;
array.mRsrcs = attrs;
AssetManager.applyStyle(mTheme, 0, resid, 0, attrs,
@@ -1365,19 +1401,18 @@
*/
public TypedArray obtainStyledAttributes(AttributeSet set,
int[] attrs, int defStyleAttr, int defStyleRes) {
- int len = attrs.length;
- TypedArray array = getCachedStyledAttributes(len);
+ final int len = attrs.length;
+ final TypedArray array = getCachedStyledAttributes(len);
// XXX note that for now we only work with compiled XML files.
// To support generic XML files we will need to manually parse
// out the attributes from the XML file (applying type information
// contained in the resources and such).
- XmlBlock.Parser parser = (XmlBlock.Parser)set;
- AssetManager.applyStyle(
- mTheme, defStyleAttr, defStyleRes,
- parser != null ? parser.mParseState : 0, attrs,
- array.mData, array.mIndices);
+ final XmlBlock.Parser parser = (XmlBlock.Parser)set;
+ AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+ parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices);
+ array.mTheme = this;
array.mRsrcs = attrs;
array.mXml = parser;
@@ -1443,6 +1478,21 @@
}
/**
+ * Return a drawable object associated with a particular resource ID
+ * and styled for the Theme.
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ * @return Drawable An object that can be used to draw this resource.
+ * @throws NotFoundException Throws NotFoundException if the given ID
+ * does not exist.
+ */
+ public Drawable getDrawable(int id) throws NotFoundException {
+ return Resources.this.getDrawable(id, this);
+ }
+
+ /**
* Print contents of this theme out to the log. For debugging only.
*
* @param priority The log priority to use.
@@ -1452,7 +1502,8 @@
public void dump(int priority, String tag, String prefix) {
AssetManager.dumpTheme(mTheme, priority, tag, prefix);
}
-
+
+ @Override
protected void finalize() throws Throwable {
super.finalize();
mAssets.releaseTheme(mTheme);
@@ -1463,6 +1514,7 @@
mTheme = mAssets.createTheme();
}
+ @SuppressWarnings("hiding")
private final AssetManager mAssets;
private final long mTheme;
}
@@ -2027,14 +2079,14 @@
return true;
}
- /*package*/ Drawable loadDrawable(TypedValue value, int id)
- throws NotFoundException {
-
+ /*package*/ Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
if (TRACE_FOR_PRELOAD) {
// Log only framework resources
if ((id >>> 24) == 0x1) {
final String name = getResourceName(id);
- if (name != null) android.util.Log.d("PreloadDrawable", name);
+ if (name != null) {
+ Log.d("PreloadDrawable", name);
+ }
}
}
@@ -2239,12 +2291,12 @@
"Resource is not a ColorStateList (color or path): " + value);
}
- String file = value.string.toString();
+ final String file = value.string.toString();
if (file.endsWith(".xml")) {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
try {
- XmlResourceParser rp = loadXmlResourceParser(
+ final XmlResourceParser rp = loadXmlResourceParser(
file, id, value.assetCookie, "colorstatelist");
csl = ColorStateList.createFromXml(this, rp);
rp.close();
@@ -2371,7 +2423,6 @@
synchronized (mAccessLock) {
final TypedArray cached = mCachedStyledAttributes;
if (cached == null || cached.mData.length < attrs.mData.length) {
- attrs.mXml = null;
mCachedStyledAttributes = attrs;
}
}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 87d65a5..4858d08 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -45,7 +45,8 @@
/*package*/ int[] mIndices;
/*package*/ int mLength;
/*package*/ TypedValue mValue = new TypedValue();
-
+ /*package*/ Resources.Theme mTheme;
+
/**
* Return the number of values in this array.
*/
@@ -600,7 +601,7 @@
+ " cookie=" + value.assetCookie);
System.out.println("******************************************************************");
}
- return mResources.loadDrawable(value, value.resourceId);
+ return mResources.loadDrawable(value, value.resourceId, mTheme);
}
return null;
}
@@ -690,6 +691,10 @@
*/
public void recycle() {
mResources.recycleCachedStyledAttributes(this);
+
+ mXml = null;
+ mRsrcs = null;
+ mTheme = null;
}
private boolean getValueAt(int index, TypedValue outValue) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 495bf51..bb8b184 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -255,20 +255,27 @@
new Key<byte[]>("android.control.awbAvailableModes", byte[].class);
/**
- * <p>For AE, AWB, and AF, how many individual
- * regions can be listed for metering?</p>
+ * <p>List of the maximum number of regions that can be used for metering in
+ * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
+ * this corresponds to the the maximum number of elements in
+ * {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}, {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions},
+ * and {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_REGIONS
+ * @see CaptureRequest#CONTROL_AF_REGIONS
+ * @see CaptureRequest#CONTROL_AWB_REGIONS
*/
- public static final Key<Integer> CONTROL_MAX_REGIONS =
- new Key<Integer>("android.control.maxRegions", int.class);
+ public static final Key<int[]> CONTROL_MAX_REGIONS =
+ new Key<int[]>("android.control.maxRegions", int[].class);
/**
- * <p>Whether this camera has a
- * flash</p>
+ * <p>Whether this camera device has a
+ * flash.</p>
* <p>If no flash, none of the flash controls do
- * anything. All other metadata should return 0</p>
+ * anything. All other metadata should return 0.</p>
*/
- public static final Key<Byte> FLASH_INFO_AVAILABLE =
- new Key<Byte>("android.flash.info.available", byte.class);
+ public static final Key<Boolean> FLASH_INFO_AVAILABLE =
+ new Key<Boolean>("android.flash.info.available", boolean.class);
/**
* <p>Supported resolutions for the JPEG thumbnail</p>
@@ -515,8 +522,9 @@
/**
* <p>Area of raw data which corresponds to only
- * active pixels; smaller or equal to
- * pixelArraySize.</p>
+ * active pixels.</p>
+ * <p>It is smaller or equal to
+ * sensor full pixel array, which could include the black calibration pixels.</p>
*/
public static final Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE =
new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class);
@@ -529,19 +537,29 @@
/**
* <p>Range of valid exposure
- * times</p>
+ * times used by {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}.</p>
+ *
+ * @see CaptureRequest#SENSOR_EXPOSURE_TIME
*/
public static final Key<long[]> SENSOR_INFO_EXPOSURE_TIME_RANGE =
new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class);
/**
* <p>Maximum possible frame duration (minimum frame
- * rate)</p>
- * <p>Minimum duration is a function of resolution,
- * processing settings. See
- * android.scaler.availableProcessedMinDurations
- * android.scaler.availableJpegMinDurations
- * android.scaler.availableRawMinDurations</p>
+ * rate).</p>
+ * <p>The largest possible android.sensor.frameDuration
+ * that will be accepted by the camera device. Attempting to use
+ * frame durations beyond the maximum will result in the frame duration
+ * being clipped to the maximum. See that control
+ * for a full definition of frame durations.</p>
+ * <p>Refer to
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations},
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations}, and
+ * android.scaler.availableRawMinDurations for the minimum
+ * frame duration values.</p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
*/
public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION =
new Key<Long>("android.sensor.info.maxFrameDuration", long.class);
@@ -569,11 +587,11 @@
/**
* <p>Maximum sensitivity that is implemented
- * purely through analog gain</p>
+ * purely through analog gain.</p>
* <p>For {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} values less than or
* equal to this, all applied gain must be analog. For
- * values above this, it can be a mix of analog and
- * digital</p>
+ * values above this, the gain applied can be a mix of analog and
+ * digital.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index e839be3..a1f432d 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1372,22 +1372,28 @@
public static final int FLASH_STATE_UNAVAILABLE = 0;
/**
- * <p>if android.flash.available is true Flash is
+ * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash is
* charging and cannot be fired</p>
+ *
+ * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_CHARGING = 1;
/**
- * <p>if android.flash.available is true Flash is
+ * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash is
* ready to fire</p>
+ *
+ * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_READY = 2;
/**
- * <p>if android.flash.available is true Flash fired
+ * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash fired
* for this capture</p>
+ *
+ * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_FIRED = 3;
@@ -1397,11 +1403,21 @@
//
/**
+ * <p>The lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, android.lens.focusDistance
+ * android.lens.filterDensity and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) are not changing.</p>
+ *
+ * @see CaptureRequest#LENS_APERTURE
+ * @see CaptureRequest#LENS_FOCAL_LENGTH
* @see CaptureResult#LENS_STATE
*/
public static final int LENS_STATE_STATIONARY = 0;
/**
+ * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, android.lens.focusDistance
+ * android.lens.filterDensity or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p>
+ *
+ * @see CaptureRequest#LENS_APERTURE
+ * @see CaptureRequest#LENS_FOCAL_LENGTH
* @see CaptureResult#LENS_STATE
*/
public static final int LENS_STATE_MOVING = 1;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 56508e8..1327ba9 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -510,9 +510,9 @@
/**
* <p>List of areas to use for
- * metering</p>
+ * metering.</p>
* <p>Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * xmax, ymax, weight. The rectangle is defined to be inclusive of the
* specified coordinates.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
@@ -524,7 +524,7 @@
* needs to be used by the HAL. If the metering region is
* outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata</p>
+ * used sections in the frame metadata.</p>
*
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -582,9 +582,9 @@
/**
* <p>List of areas to use for focus
- * estimation</p>
+ * estimation.</p>
* <p>Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * xmax, ymax, weight. The rectangle is defined to be inclusive of the
* specified coordinates.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
@@ -596,7 +596,7 @@
* needs to be used by the HAL. If the focusing region is
* outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata</p>
+ * used sections in the frame metadata.</p>
*
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -668,10 +668,10 @@
/**
* <p>List of areas to use for illuminant
- * estimation</p>
+ * estimation.</p>
* <p>Only used in AUTO mode.</p>
* <p>Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * xmax, ymax, weight. The rectangle is defined to be inclusive of the
* specified coordinates.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
@@ -683,7 +683,7 @@
* needs to be used by the HAL. If the metering region is
* outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata</p>
+ * used sections in the frame metadata.</p>
*
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -826,7 +826,7 @@
/**
* <p>The desired mode for for the camera device's flash control.</p>
* <p>This control is only effective when flash unit is available
- * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} != 0</code>).</p>
+ * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == true</code>).</p>
* <p>When this control is used, the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} must be set to ON or OFF.
* Otherwise, the camera device auto-exposure related flash control (ON_AUTO_FLASH,
* ON_ALWAYS_FLASH, or ON_AUTO_FLASH_REDEYE) will override this control.</p>
@@ -837,10 +837,12 @@
* ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p>
* <p>When set to TORCH, the flash will be on continuously. This mode can be used
* for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
+ * <p>The flash status will be reported by {@link CaptureResult#FLASH_STATE android.flash.state} in the capture result metadata.</p>
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
* @see CameraCharacteristics#FLASH_INFO_AVAILABLE
+ * @see CaptureResult#FLASH_STATE
* @see #FLASH_MODE_OFF
* @see #FLASH_MODE_SINGLE
* @see #FLASH_MODE_TORCH
@@ -913,7 +915,8 @@
* to achieve manual exposure control.</p>
* <p>The requested aperture value may take several frames to reach the
* requested value; the camera device will report the current (intermediate)
- * aperture size in capture result metadata while the aperture is changing.</p>
+ * aperture size in capture result metadata while the aperture is changing.
+ * While the aperture is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
* <p>When this is supported and {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is one of
* the ON modes, this will be overridden by the camera device
* auto-exposure algorithm, the overridden values are then provided
@@ -921,6 +924,7 @@
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES
+ * @see CaptureResult#LENS_STATE
* @see CaptureRequest#SENSOR_EXPOSURE_TIME
* @see CaptureRequest#SENSOR_SENSITIVITY
*/
@@ -940,8 +944,12 @@
* in no reduction of the incoming light, and setting this to 2 would
* mean that the filter is set to reduce incoming light by two stops
* (allowing 1/4 of the prior amount of light to the sensor).</p>
+ * <p>It may take several frames before the lens filter density changes
+ * to the requested value. While the filter density is still changing,
+ * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
*
* @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES
+ * @see CaptureResult#LENS_STATE
*/
public static final Key<Float> LENS_FILTER_DENSITY =
new Key<Float>("android.lens.filterDensity", float.class);
@@ -953,7 +961,7 @@
* view of the camera device, and is usually used for optical zoom.</p>
* <p>Like {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, this
* setting won't be applied instantaneously, and it may take several
- * frames before the lens can move to the requested focal length.
+ * frames before the lens can change to the requested focal length.
* While the focal length is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will
* be set to MOVING.</p>
* <p>This is expected not to be supported on most devices.</p>
@@ -968,8 +976,16 @@
/**
* <p>Distance to plane of sharpest focus,
* measured from frontmost surface of the lens</p>
- * <p>0 = infinity focus. Used value should be clamped
- * to (0,minimum focus distance)</p>
+ * <p>0 means infinity focus. Used value will be clamped
+ * to [0, {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}].</p>
+ * <p>Like {@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, this setting won't be applied
+ * instantaneously, and it may take several frames before the lens
+ * can move to the requested focus distance. While the lens is still moving,
+ * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
+ *
+ * @see CaptureRequest#LENS_FOCAL_LENGTH
+ * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
+ * @see CaptureResult#LENS_STATE
*/
public static final Key<Float> LENS_FOCUS_DISTANCE =
new Key<Float>("android.lens.focusDistance", float.class);
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0ded5bd..46d95b1 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -212,9 +212,9 @@
/**
* <p>List of areas to use for
- * metering</p>
+ * metering.</p>
* <p>Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * xmax, ymax, weight. The rectangle is defined to be inclusive of the
* specified coordinates.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
@@ -226,7 +226,7 @@
* needs to be used by the HAL. If the metering region is
* outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata</p>
+ * used sections in the frame metadata.</p>
*
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -405,9 +405,9 @@
/**
* <p>List of areas to use for focus
- * estimation</p>
+ * estimation.</p>
* <p>Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * xmax, ymax, weight. The rectangle is defined to be inclusive of the
* specified coordinates.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
@@ -419,7 +419,7 @@
* needs to be used by the HAL. If the focusing region is
* outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata</p>
+ * used sections in the frame metadata.</p>
*
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -794,10 +794,10 @@
/**
* <p>List of areas to use for illuminant
- * estimation</p>
+ * estimation.</p>
* <p>Only used in AUTO mode.</p>
* <p>Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * xmax, ymax, weight. The rectangle is defined to be inclusive of the
* specified coordinates.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
@@ -809,7 +809,7 @@
* needs to be used by the HAL. If the metering region is
* outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata</p>
+ * used sections in the frame metadata.</p>
*
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -965,7 +965,7 @@
/**
* <p>The desired mode for for the camera device's flash control.</p>
* <p>This control is only effective when flash unit is available
- * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} != 0</code>).</p>
+ * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == true</code>).</p>
* <p>When this control is used, the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} must be set to ON or OFF.
* Otherwise, the camera device auto-exposure related flash control (ON_AUTO_FLASH,
* ON_ALWAYS_FLASH, or ON_AUTO_FLASH_REDEYE) will override this control.</p>
@@ -976,10 +976,12 @@
* ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p>
* <p>When set to TORCH, the flash will be on continuously. This mode can be used
* for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
+ * <p>The flash status will be reported by {@link CaptureResult#FLASH_STATE android.flash.state} in the capture result metadata.</p>
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
* @see CameraCharacteristics#FLASH_INFO_AVAILABLE
+ * @see CaptureResult#FLASH_STATE
* @see #FLASH_MODE_OFF
* @see #FLASH_MODE_SINGLE
* @see #FLASH_MODE_TORCH
@@ -989,7 +991,12 @@
/**
* <p>Current state of the flash
- * unit</p>
+ * unit.</p>
+ * <p>When the camera device doesn't have flash unit
+ * (i.e. <code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == false</code>), this state will always be UNAVAILABLE.
+ * Other states indicate the current flash status.</p>
+ *
+ * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
* @see #FLASH_STATE_UNAVAILABLE
* @see #FLASH_STATE_CHARGING
* @see #FLASH_STATE_READY
@@ -1063,7 +1070,8 @@
* to achieve manual exposure control.</p>
* <p>The requested aperture value may take several frames to reach the
* requested value; the camera device will report the current (intermediate)
- * aperture size in capture result metadata while the aperture is changing.</p>
+ * aperture size in capture result metadata while the aperture is changing.
+ * While the aperture is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
* <p>When this is supported and {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is one of
* the ON modes, this will be overridden by the camera device
* auto-exposure algorithm, the overridden values are then provided
@@ -1071,6 +1079,7 @@
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES
+ * @see CaptureResult#LENS_STATE
* @see CaptureRequest#SENSOR_EXPOSURE_TIME
* @see CaptureRequest#SENSOR_SENSITIVITY
*/
@@ -1090,8 +1099,12 @@
* in no reduction of the incoming light, and setting this to 2 would
* mean that the filter is set to reduce incoming light by two stops
* (allowing 1/4 of the prior amount of light to the sensor).</p>
+ * <p>It may take several frames before the lens filter density changes
+ * to the requested value. While the filter density is still changing,
+ * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
*
* @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES
+ * @see CaptureResult#LENS_STATE
*/
public static final Key<Float> LENS_FILTER_DENSITY =
new Key<Float>("android.lens.filterDensity", float.class);
@@ -1103,7 +1116,7 @@
* view of the camera device, and is usually used for optical zoom.</p>
* <p>Like {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, this
* setting won't be applied instantaneously, and it may take several
- * frames before the lens can move to the requested focal length.
+ * frames before the lens can change to the requested focal length.
* While the focal length is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will
* be set to MOVING.</p>
* <p>This is expected not to be supported on most devices.</p>
@@ -1148,7 +1161,35 @@
new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
/**
- * <p>Current lens status</p>
+ * <p>Current lens status.</p>
+ * <p>For lens parameters {@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+ * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, when changes are requested,
+ * they may take several frames to reach the requested values. This state indicates
+ * the current status of the lens parameters.</p>
+ * <p>When the state is STATIONARY, the lens parameters are not changing. This could be
+ * either because the parameters are all fixed, or because the lens has had enough
+ * time to reach the most recently-requested values.
+ * If all these lens parameters are not changable for a camera device, as listed below:</p>
+ * <ul>
+ * <li>Fixed focus (<code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} == 0</code>), which means
+ * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} parameter will always be 0.</li>
+ * <li>Fixed focal length ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS android.lens.info.availableFocalLengths} contains single value),
+ * which means the optical zoom is not supported.</li>
+ * <li>No ND filter ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES android.lens.info.availableFilterDensities} contains only 0).</li>
+ * <li>Fixed aperture ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES android.lens.info.availableApertures} contains single value).</li>
+ * </ul>
+ * <p>Then this state will always be STATIONARY.</p>
+ * <p>When the state is MOVING, it indicates that at least one of the lens parameters
+ * is changing.</p>
+ *
+ * @see CaptureRequest#LENS_APERTURE
+ * @see CaptureRequest#LENS_FILTER_DENSITY
+ * @see CaptureRequest#LENS_FOCAL_LENGTH
+ * @see CaptureRequest#LENS_FOCUS_DISTANCE
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS
+ * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
* @see #LENS_STATE_STATIONARY
* @see #LENS_STATE_MOVING
*/
@@ -1593,10 +1634,24 @@
new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class);
/**
- * <p>The HAL estimated scene illumination lighting
- * frequency</p>
- * <p>Report NONE if there doesn't appear to be flickering
- * illumination</p>
+ * <p>The camera device estimated scene illumination lighting
+ * frequency.</p>
+ * <p>Many light sources, such as most fluorescent lights, flicker at a rate
+ * that depends on the local utility power standards. This flicker must be
+ * accounted for by auto-exposure routines to avoid artifacts in captured images.
+ * The camera device uses this entry to tell the application what the scene
+ * illuminant frequency is.</p>
+ * <p>When manual exposure control is enabled
+ * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == OFF</code>),
+ * the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't do the antibanding, and the
+ * application can ensure it selects exposure times that do not cause banding
+ * issues by looking into this metadata field. See android.control.aeAntibandingMode
+ * for more details.</p>
+ * <p>Report NONE if there doesn't appear to be flickering illumination.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#CONTROL_MODE
* @see #STATISTICS_SCENE_FLICKER_NONE
* @see #STATISTICS_SCENE_FLICKER_50HZ
* @see #STATISTICS_SCENE_FLICKER_60HZ
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6ac126e..3a35cb9 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -800,6 +800,8 @@
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface. An attempt to add a route that
* already exists is ignored, but treated as successful.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
* @param networkType the type of the network over which traffic to the specified
* host is to be routed
* @param hostAddress the IP address of the host to which the route is desired
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index d9c35c0..3c3d8ec 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -306,18 +306,18 @@
if (VDBG) {
Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged");
if (mNetworkInfo != null) {
- Slog.d(TAG, "NetworkInfo = " + mNetworkInfo.toString());
- Slog.d(TAG, "subType = " + String.valueOf(mNetworkInfo.getSubtype()));
+ Slog.d(TAG, "NetworkInfo = " + mNetworkInfo);
+ Slog.d(TAG, "subType = " + mNetworkInfo.getSubtype());
Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName());
}
if (mLinkProperties != null) {
- Slog.d(TAG, "LinkProperties = " + mLinkProperties.toString());
+ Slog.d(TAG, "LinkProperties = " + mLinkProperties);
} else {
Slog.d(TAG, "LinkProperties = " );
}
if (mLinkCapabilities != null) {
- Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities.toString());
+ Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities);
} else {
Slog.d(TAG, "LinkCapabilities = " );
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 2afea1f..27c0f5d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -452,6 +452,56 @@
}
}
+ public final static class HistoryTag {
+ public String string;
+ public int uid;
+
+ public int poolIdx;
+
+ public void setTo(HistoryTag o) {
+ string = o.string;
+ uid = o.uid;
+ poolIdx = o.poolIdx;
+ }
+
+ public void setTo(String _string, int _uid) {
+ string = _string;
+ uid = _uid;
+ poolIdx = -1;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(string);
+ dest.writeInt(uid);
+ }
+
+ public void readFromParcel(Parcel src) {
+ string = src.readString();
+ uid = src.readInt();
+ poolIdx = -1;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ HistoryTag that = (HistoryTag) o;
+
+ if (uid != that.uid) return false;
+ if (!string.equals(that.string)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = string.hashCode();
+ result = 31 * result + uid;
+ return result;
+ }
+ }
+
public final static class HistoryItem implements Parcelable {
public HistoryItem next;
@@ -500,7 +550,7 @@
public static final int STATE_PHONE_STATE_MASK = 0x7 << STATE_PHONE_STATE_SHIFT;
// Constants from DATA_CONNECTION_*
public static final int STATE_DATA_CONNECTION_SHIFT = 9;
- public static final int STATE_DATA_CONNECTION_MASK = 0x1f;
+ public static final int STATE_DATA_CONNECTION_MASK = 0x1f << STATE_DATA_CONNECTION_SHIFT;
// These states always appear directly in the first int token
// of a delta change; they should be ones that change relatively
@@ -529,21 +579,30 @@
public int states;
+ // The wake lock that was acquired at this point.
+ public HistoryTag wakelockTag;
+
public static final int EVENT_NONE = 0;
public static final int EVENT_PROC_STARTED = 1;
public static final int EVENT_PROC_FINISHED = 2;
// For CMD_EVENT.
public int eventCode;
- public String eventName;
- public int eventNameIdx; // only filled in when iterating.
- public int eventUid;
+ public HistoryTag eventTag;
+
+ // Meta-data when reading.
+ public int numReadInts;
+
+ // Pre-allocated objects.
+ public final HistoryTag localWakelockTag = new HistoryTag();
+ public final HistoryTag localEventTag = new HistoryTag();
public HistoryItem() {
}
public HistoryItem(long time, Parcel src) {
this.time = time;
+ numReadInts = 2;
readFromParcel(src);
}
@@ -563,14 +622,20 @@
| ((((int)batteryVoltage)<<16)&0xffff0000);
dest.writeInt(bat);
dest.writeInt(states);
+ if (wakelockTag != null) {
+ dest.writeInt(1);
+ wakelockTag.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
if (cmd == CMD_EVENT) {
dest.writeInt(eventCode);
- dest.writeInt(eventUid);
- dest.writeString(eventName);
+ eventTag.writeToParcel(dest, flags);
}
}
public void readFromParcel(Parcel src) {
+ int start = src.dataPosition();
int bat = src.readInt();
cmd = (byte)(bat&0xff);
batteryLevel = (byte)((bat>>8)&0xff);
@@ -581,14 +646,21 @@
batteryTemperature = (short)(bat&0xffff);
batteryVoltage = (char)((bat>>16)&0xffff);
states = src.readInt();
+ if (src.readInt() != 0) {
+ wakelockTag = localWakelockTag;
+ wakelockTag.readFromParcel(src);
+ } else {
+ wakelockTag = null;
+ }
if (cmd == CMD_EVENT) {
eventCode = src.readInt();
- eventUid = src.readInt();
- eventName = src.readString();
- eventNameIdx = 0;
+ eventTag = localEventTag;
+ eventTag.readFromParcel(src);
} else {
eventCode = EVENT_NONE;
+ eventTag = null;
}
+ numReadInts += (src.dataPosition()-start)/4;
}
public void clear() {
@@ -601,9 +673,9 @@
batteryTemperature = 0;
batteryVoltage = 0;
states = 0;
+ wakelockTag = null;
eventCode = EVENT_NONE;
- eventUid = 0;
- eventName = null;
+ eventTag = null;
}
public void setTo(HistoryItem o) {
@@ -616,10 +688,19 @@
batteryTemperature = o.batteryTemperature;
batteryVoltage = o.batteryVoltage;
states = o.states;
+ if (o.wakelockTag != null) {
+ wakelockTag = localWakelockTag;
+ wakelockTag.setTo(o.wakelockTag);
+ } else {
+ wakelockTag = null;
+ }
eventCode = o.eventCode;
- eventUid = o.eventUid;
- eventName = o.eventName;
- eventNameIdx = o.eventNameIdx;
+ if (o.eventTag != null) {
+ eventTag = localEventTag;
+ eventTag.setTo(o.eventTag);
+ } else {
+ eventTag = null;
+ }
}
public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName,
@@ -627,9 +708,12 @@
this.time = time;
this.cmd = cmd;
this.eventCode = eventCode;
- this.eventUid = eventUid;
- this.eventName = eventName;
- this.eventNameIdx = 0;
+ if (eventCode != EVENT_NONE) {
+ eventTag = localEventTag;
+ eventTag.setTo(eventName, eventUid);
+ } else {
+ eventTag = null;
+ }
batteryLevel = o.batteryLevel;
batteryStatus = o.batteryStatus;
batteryHealth = o.batteryHealth;
@@ -637,6 +721,12 @@
batteryTemperature = o.batteryTemperature;
batteryVoltage = o.batteryVoltage;
states = o.states;
+ if (o.wakelockTag != null) {
+ wakelockTag = localWakelockTag;
+ wakelockTag.setTo(o.wakelockTag);
+ } else {
+ wakelockTag = null;
+ }
}
public boolean sameNonEvent(HistoryItem o) {
@@ -650,13 +740,26 @@
}
public boolean same(HistoryItem o) {
- if (!sameNonEvent(o) || eventCode != o.eventCode || eventUid != o.eventUid) {
+ if (!sameNonEvent(o) || eventCode != o.eventCode) {
return false;
}
- if (eventName == o.eventName) {
- return true;
+ if (wakelockTag != o.wakelockTag) {
+ if (wakelockTag == null || o.wakelockTag == null) {
+ return false;
+ }
+ if (!wakelockTag.equals(o.wakelockTag)) {
+ return false;
+ }
}
- return eventName != null && o.eventName != null && eventName.equals(o.eventName);
+ if (eventTag != o.eventTag) {
+ if (eventTag == null || o.eventTag == null) {
+ return false;
+ }
+ if (!eventTag.equals(o.eventTag)) {
+ return false;
+ }
+ }
+ return true;
}
}
@@ -688,11 +791,19 @@
}
}
+ public abstract int getHistoryTotalSize();
+
+ public abstract int getHistoryUsedSize();
+
public abstract boolean startIteratingHistoryLocked();
public abstract int getHistoryStringPoolSize();
- public abstract String getHistoryStringPoolItem(int index);
+ public abstract int getHistoryStringPoolBytes();
+
+ public abstract String getHistoryTagPoolString(int index);
+
+ public abstract int getHistoryTagPoolUid(int index);
public abstract boolean getNextHistoryLocked(HistoryItem out);
@@ -1746,14 +1857,14 @@
sb.setLength(0);
sb.append(prefix);
- sb.append(" Signal levels: ");
+ sb.append(" Signal levels:");
didOne = false;
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which);
if (time == 0) {
continue;
}
- if (didOne) sb.append(", ");
+ sb.append("\n ");
didOne = true;
sb.append(SignalStrength.SIGNAL_STRENGTH_NAMES[i]);
sb.append(" ");
@@ -1764,7 +1875,7 @@
sb.append(getPhoneSignalStrengthCount(i, which));
sb.append("x");
}
- if (!didOne) sb.append("No activity");
+ if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
sb.setLength(0);
@@ -1775,14 +1886,14 @@
sb.setLength(0);
sb.append(prefix);
- sb.append(" Radio types: ");
+ sb.append(" Radio types:");
didOne = false;
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
final long time = getPhoneDataConnectionTime(i, batteryRealtime, which);
if (time == 0) {
continue;
}
- if (didOne) sb.append(", ");
+ sb.append("\n ");
didOne = true;
sb.append(DATA_CONNECTION_NAMES[i]);
sb.append(" ");
@@ -1793,7 +1904,7 @@
sb.append(getPhoneDataConnectionCount(i, which));
sb.append("x");
}
- if (!didOne) sb.append("No activity");
+ if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
sb.setLength(0);
@@ -2259,21 +2370,30 @@
}
}
- static void printBitDescriptions(PrintWriter pw, int oldval, int newval,
+ static void printBitDescriptions(PrintWriter pw, int oldval, int newval, HistoryTag wakelockTag,
BitDescription[] descriptions, boolean longNames) {
int diff = oldval ^ newval;
if (diff == 0) return;
+ boolean didWake = false;
for (int i=0; i<descriptions.length; i++) {
BitDescription bd = descriptions[i];
- int mask = bd.mask;
- if (bd.shift > 0) {
- mask <<= bd.shift;
- }
- if ((diff&mask) != 0) {
+ if ((diff&bd.mask) != 0) {
pw.print(longNames ? " " : ",");
if (bd.shift < 0) {
- pw.print((newval&mask) != 0 ? "+" : "-");
+ pw.print((newval&bd.mask) != 0 ? "+" : "-");
pw.print(longNames ? bd.name : bd.shortName);
+ if (bd.mask == HistoryItem.STATE_WAKE_LOCK_FLAG && wakelockTag != null) {
+ didWake = true;
+ pw.print("=");
+ if (longNames) {
+ UserHandle.formatUid(pw, wakelockTag.uid);
+ pw.print(":\"");
+ pw.print(wakelockTag.string);
+ pw.print("\"");
+ } else {
+ pw.print(wakelockTag.poolIdx);
+ }
+ }
} else {
pw.print(longNames ? bd.name : bd.shortName);
pw.print("=");
@@ -2286,6 +2406,17 @@
}
}
}
+ if (!didWake && wakelockTag != null) {
+ pw.print(longNames ? "wake_lock=" : "w=");
+ if (longNames) {
+ UserHandle.formatUid(pw, wakelockTag.uid);
+ pw.print(":\"");
+ pw.print(wakelockTag.string);
+ pw.print("\"");
+ } else {
+ pw.print(wakelockTag.poolIdx);
+ }
+ }
}
public void prepareForDumpLocked() {
@@ -2305,7 +2436,9 @@
if (!checkin) {
pw.print(" ");
TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
- pw.print(" ");
+ pw.print(" (");
+ pw.print(rec.numReadInts);
+ pw.print(") ");
} else {
if (lastTime < 0) {
pw.print("@");
@@ -2427,7 +2560,7 @@
pw.print(checkin ? ",Bv=" : " volt=");
pw.print(oldVolt);
}
- printBitDescriptions(pw, oldState, rec.states,
+ printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag,
HISTORY_STATE_DESCRIPTIONS, !checkin);
if (rec.eventCode != HistoryItem.EVENT_NONE) {
switch (rec.eventCode) {
@@ -2450,15 +2583,12 @@
break;
}
if (checkin) {
- pw.print(rec.eventUid);
+ pw.print(rec.eventTag.poolIdx);
} else {
- UserHandle.formatUid(pw, rec.eventUid);
- }
- pw.print(":");
- if (checkin) {
- pw.print(rec.eventNameIdx);
- } else {
- pw.print(rec.eventName);
+ UserHandle.formatUid(pw, rec.eventTag.uid);
+ pw.print(":\"");
+ pw.print(rec.eventTag.string);
+ pw.print("\"");
}
}
pw.println();
@@ -2467,6 +2597,33 @@
}
}
+ private void printSizeValue(PrintWriter pw, long size) {
+ float result = size;
+ String suffix = "";
+ if (result >= 10*1024) {
+ suffix = "KB";
+ result = result / 1024;
+ }
+ if (result >= 10*1024) {
+ suffix = "MB";
+ result = result / 1024;
+ }
+ if (result >= 10*1024) {
+ suffix = "GB";
+ result = result / 1024;
+ }
+ if (result >= 10*1024) {
+ suffix = "TB";
+ result = result / 1024;
+ }
+ if (result >= 10*1024) {
+ suffix = "PB";
+ result = result / 1024;
+ }
+ pw.print((int)result);
+ pw.print(suffix);
+ }
+
/**
* Dumps a human-readable summary of the battery statistics to the given PrintWriter.
*
@@ -2480,24 +2637,42 @@
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
final HistoryItem rec = new HistoryItem();
+ final long historyTotalSize = getHistoryTotalSize();
+ final long historyUsedSize = getHistoryUsedSize();
if (startIteratingHistoryLocked()) {
- pw.println("Battery History:");
- HistoryPrinter hprinter = new HistoryPrinter();
- while (getNextHistoryLocked(rec)) {
- hprinter.printNextItem(pw, rec, now, false);
+ try {
+ pw.print("Battery History (");
+ pw.print((100*historyUsedSize)/historyTotalSize);
+ pw.print("% used, ");
+ printSizeValue(pw, historyUsedSize);
+ pw.print(" used of ");
+ printSizeValue(pw, historyTotalSize);
+ pw.print(", ");
+ pw.print(getHistoryStringPoolSize());
+ pw.print(" strings using ");
+ printSizeValue(pw, getHistoryStringPoolBytes());
+ pw.println("):");
+ HistoryPrinter hprinter = new HistoryPrinter();
+ while (getNextHistoryLocked(rec)) {
+ hprinter.printNextItem(pw, rec, now, false);
+ }
+ pw.println();
+ } finally {
+ finishIteratingHistoryLocked();
}
- finishIteratingHistoryLocked();
- pw.println("");
}
if (startIteratingOldHistoryLocked()) {
- pw.println("Old battery History:");
- HistoryPrinter hprinter = new HistoryPrinter();
- while (getNextOldHistoryLocked(rec)) {
- hprinter.printNextItem(pw, rec, now, false);
+ try {
+ pw.println("Old battery History:");
+ HistoryPrinter hprinter = new HistoryPrinter();
+ while (getNextOldHistoryLocked(rec)) {
+ hprinter.printNextItem(pw, rec, now, false);
+ }
+ pw.println();
+ } finally {
+ finishIteratingOldHistoryLocked();
}
- finishIteratingOldHistoryLocked();
- pw.println("");
}
if (historyOnly) {
@@ -2553,21 +2728,26 @@
if (includeHistory || historyOnly) {
final HistoryItem rec = new HistoryItem();
if (startIteratingHistoryLocked()) {
- for (int i=0; i<getHistoryStringPoolSize(); i++) {
- pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
- pw.print(HISTORY_STRING_POOL); pw.print(',');
- pw.print(i);
- pw.print(',');
- pw.print(getHistoryStringPoolItem(i));
- pw.println();
+ try {
+ for (int i=0; i<getHistoryStringPoolSize(); i++) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(HISTORY_STRING_POOL); pw.print(',');
+ pw.print(i);
+ pw.print(',');
+ pw.print(getHistoryTagPoolString(i));
+ pw.print(',');
+ pw.print(getHistoryTagPoolUid(i));
+ pw.println();
+ }
+ HistoryPrinter hprinter = new HistoryPrinter();
+ while (getNextHistoryLocked(rec)) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(HISTORY_DATA); pw.print(',');
+ hprinter.printNextItem(pw, rec, now, true);
+ }
+ } finally {
+ finishIteratingHistoryLocked();
}
- HistoryPrinter hprinter = new HistoryPrinter();
- while (getNextHistoryLocked(rec)) {
- pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
- pw.print(HISTORY_DATA); pw.print(',');
- hprinter.printNextItem(pw, rec, now, true);
- }
- finishIteratingHistoryLocked();
}
}
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 5275bc0..b65eac7 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -169,7 +169,7 @@
* @param dialogIconRes The icon, as a resource ID.
*/
public void setDialogIcon(int dialogIconRes) {
- mDialogIcon = getContext().getResources().getDrawable(dialogIconRes);
+ mDialogIcon = getContext().getDrawable(dialogIconRes);
}
/**
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 76fccc7..144c909 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -561,7 +561,7 @@
if (imageView != null) {
if (mIconResId != 0 || mIcon != null) {
if (mIcon == null) {
- mIcon = getContext().getResources().getDrawable(mIconResId);
+ mIcon = getContext().getDrawable(mIconResId);
}
if (mIcon != null) {
imageView.setImageDrawable(mIcon);
@@ -694,7 +694,7 @@
*/
public void setIcon(int iconResId) {
mIconResId = iconResId;
- setIcon(mContext.getResources().getDrawable(iconResId));
+ setIcon(mContext.getDrawable(iconResId));
}
/**
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 74b9463..3d6f8e6 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -145,7 +145,7 @@
}
} else {
try {
- drawable = mContext.getResources().getDrawable(mResourceId);
+ drawable = mContext.getDrawable(mResourceId);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
} catch (Exception e) {
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index da9ba5a..fd3f9b3 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -552,7 +552,8 @@
return false;
}
- private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
+ /** @hide */
+ public static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
if (runningAnimators == null) {
runningAnimators = new ArrayMap<Animator, AnimationInfo>();
@@ -1077,6 +1078,9 @@
if (view == null) {
return;
}
+ if (!isValidTarget(view, view.getId())) {
+ return;
+ }
boolean isListViewItem = false;
if (view.getParent() instanceof ListView) {
isListViewItem = true;
@@ -1467,6 +1471,10 @@
mCanRemoveViews = canRemoveViews;
}
+ public boolean canRemoveViews() {
+ return mCanRemoveViews;
+ }
+
@Override
public String toString() {
return toString("");
@@ -1629,9 +1637,10 @@
* animation should be canceled or a new animation noop'd. The structure holds
* information about the state that an animation is going to, to be compared to
* end state of a new animation.
+ * @hide
*/
- private static class AnimationInfo {
- View view;
+ public static class AnimationInfo {
+ public View view;
String name;
TransitionValues values;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index ed75850..aaa8b8c 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -91,7 +91,8 @@
private static final String TAG_1995 = "blink";
private static final String TAG_REQUEST_FOCUS = "requestFocus";
- private static final String ATTR_THEME = "theme";
+ private static final int[] ATTRS_THEME = new int[] {
+ com.android.internal.R.attr.theme };
/**
* Hook to allow clients of the LayoutInflater to restrict the set of Views that are allowed
@@ -689,10 +690,12 @@
}
// Apply a theme wrapper, if requested.
- final int themeResId = attrs.getAttributeResourceValue(null, ATTR_THEME, 0);
+ final TypedArray ta = viewContext.obtainStyledAttributes(attrs, ATTRS_THEME);
+ final int themeResId = ta.getResourceId(0, 0);
if (themeResId != 0) {
viewContext = new ContextThemeWrapper(viewContext, themeResId);
}
+ ta.recycle();
if (name.equals(TAG_1995)) {
// Let's party like it's 1995!
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index bb7ed41..063a08d 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -140,7 +140,7 @@
if ((resourceId & 0xff000000) == 0x01000000) {
icon.mSystemIconResourceId = resourceId;
} else {
- icon.loadResource(context.getResources(), resourceId);
+ icon.loadResource(context, context.getResources(), resourceId);
}
return icon;
}
@@ -198,7 +198,7 @@
}
PointerIcon icon = new PointerIcon(STYLE_CUSTOM);
- icon.loadResource(resources, resourceId);
+ icon.loadResource(null, resources, resourceId);
return icon;
}
@@ -224,7 +224,7 @@
PointerIcon result = new PointerIcon(mStyle);
result.mSystemIconResourceId = mSystemIconResourceId;
- result.loadResource(context.getResources(), mSystemIconResourceId);
+ result.loadResource(context, context.getResources(), mSystemIconResourceId);
return result;
}
@@ -373,7 +373,7 @@
return true;
}
- private void loadResource(Resources resources, int resourceId) {
+ private void loadResource(Context context, Resources resources, int resourceId) {
XmlResourceParser parser = resources.getXml(resourceId);
final int bitmapRes;
final float hotSpotX;
@@ -397,7 +397,12 @@
throw new IllegalArgumentException("<pointer-icon> is missing bitmap attribute.");
}
- Drawable drawable = resources.getDrawable(bitmapRes);
+ Drawable drawable;
+ if (context == null) {
+ drawable = resources.getDrawable(bitmapRes);
+ } else {
+ drawable = context.getDrawable(bitmapRes);
+ }
if (!(drawable instanceof BitmapDrawable)) {
throw new IllegalArgumentException("<pointer-icon> bitmap attribute must "
+ "refer to a bitmap drawable.");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 55dcbb2..97a1f21 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -177,13 +177,13 @@
* Equivalent to calling hide().
* Updates the value set during Surface creation (see {@link #HIDDEN}).
*/
- public static final int SURFACE_HIDDEN = 0x01;
+ private static final int SURFACE_HIDDEN = 0x01;
/**
* Surface flag: composite without blending when possible.
* Updates the value set during Surface creation (see {@link #OPAQUE}).
*/
- public static final int SURFACE_OPAQUE = 0x02;
+ private static final int SURFACE_OPAQUE = 0x02;
/* built-in physical display ids (keep in sync with ISurfaceComposer.h)
@@ -191,13 +191,13 @@
/**
* Built-in physical display id: Main display.
- * Use only with {@link SurfaceControl#getBuiltInDisplay()}.
+ * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
*/
public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
/**
* Built-in physical display id: Attached HDMI display.
- * Use only with {@link SurfaceControl#getBuiltInDisplay()}.
+ * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
*/
public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
@@ -369,18 +369,6 @@
nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy);
}
- /**
- * Sets and clears flags, such as {@link #SURFACE_HIDDEN}. The new value will be:
- * <p>
- * <code>newFlags = (oldFlags & ~mask) | (flags & mask)</code>
- * <p>
- * Note this does not take the same set of flags as the constructor.
- */
- public void setFlags(int flags, int mask) {
- checkNotReleased();
- nativeSetFlags(mNativeObject, flags, mask);
- }
-
public void setWindowCrop(Rect crop) {
checkNotReleased();
if (crop != null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 239eda4..518908f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -665,6 +665,7 @@
* @attr ref android.R.styleable#View_scrollbarTrackVertical
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
+ * @attr ref android.R.styleable#View_sharedElementName
* @attr ref android.R.styleable#View_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
* @attr ref android.R.styleable#View_textAlignment
@@ -2325,7 +2326,18 @@
/* End of masks for mPrivateFlags2 */
- /* Masks for mPrivateFlags3 */
+ /**
+ * Masks for mPrivateFlags3, as generated by dumpFlags():
+ *
+ * |-------|-------|-------|-------|
+ * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM
+ * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA
+ * 1 PFLAG3_IS_LAID_OUT
+ * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT
+ * 1 PFLAG3_CALLED_SUPER
+ * 1 PFLAG3_PROJECT_BACKGROUND
+ * |-------|-------|-------|-------|
+ */
/**
* Flag indicating that view has a transform animation set on it. This is used to track whether
@@ -2359,6 +2371,11 @@
*/
static final int PFLAG3_CALLED_SUPER = 0x10;
+ /**
+ * Flag indicating that the background of this view will be drawn into a
+ * display list and projected onto the closest parent projection surface.
+ */
+ static final int PFLAG3_PROJECT_BACKGROUND = 0x20;
/* End of masks for mPrivateFlags3 */
@@ -3225,6 +3242,15 @@
@ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
private Drawable mBackground;
+ /**
+ * Display list used for backgrounds.
+ * <p>
+ * When non-null and valid, this is expected to contain an up-to-date copy
+ * of the background drawable. It is cleared on temporary detach and reset
+ * on cleanup.
+ */
+ private DisplayList mBackgroundDisplayList;
+
private int mBackgroundResource;
private boolean mBackgroundSizeChanged;
@@ -3503,6 +3529,13 @@
private Bitmap mDrawingCache;
private Bitmap mUnscaledDrawingCache;
+ /**
+ * Display list used for the View content.
+ * <p>
+ * When non-null and valid, this is expected to contain an up-to-date copy
+ * of the View content. It is cleared on temporary detach and reset on
+ * cleanup.
+ */
DisplayList mDisplayList;
/**
@@ -4006,6 +4039,9 @@
case R.styleable.View_accessibilityLiveRegion:
setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
break;
+ case R.styleable.View_sharedElementName:
+ setSharedElementName(a.getString(attr));
+ break;
}
}
@@ -13688,12 +13724,20 @@
if (mDisplayList != null) {
mDisplayList.clear();
}
+
+ if (mBackgroundDisplayList != null) {
+ mBackgroundDisplayList.clear();
+ }
}
private void resetDisplayList() {
if (mDisplayList != null) {
mDisplayList.reset();
}
+
+ if (mBackgroundDisplayList != null) {
+ mBackgroundDisplayList.reset();
+ }
}
/**
@@ -14721,24 +14765,7 @@
int saveCount;
if (!dirtyOpaque) {
- final Drawable background = mBackground;
- if (background != null) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
-
- if (mBackgroundSizeChanged) {
- background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
- mBackgroundSizeChanged = false;
- }
-
- if ((scrollX | scrollY) == 0) {
- background.draw(canvas);
- } else {
- canvas.translate(scrollX, scrollY);
- background.draw(canvas);
- canvas.translate(-scrollX, -scrollY);
- }
- }
+ drawBackground(canvas);
}
// skip step 2 & 5 if possible (common case)
@@ -14905,6 +14932,93 @@
}
/**
+ * Draws the background onto the specified canvas.
+ *
+ * @param canvas Canvas on which to draw the background
+ */
+ private void drawBackground(Canvas canvas) {
+ final Drawable background = mBackground;
+ if (background == null) {
+ return;
+ }
+
+ if (mBackgroundSizeChanged) {
+ // We should see the background invalidate itself, but just to be
+ // careful we're going to clear the display list and force redraw.
+ if (mBackgroundDisplayList != null) {
+ mBackgroundDisplayList.clear();
+ }
+
+ background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
+ mBackgroundSizeChanged = false;
+ }
+
+
+ // Attempt to use a display list if requested.
+ if (canvas != null && canvas.isHardwareAccelerated()) {
+ mBackgroundDisplayList = getDrawableDisplayList(background, mBackgroundDisplayList);
+
+ final DisplayList displayList = mBackgroundDisplayList;
+ if (displayList != null && displayList.isValid()) {
+ setBackgroundDisplayListProperties(displayList);
+ ((HardwareCanvas) canvas).drawDisplayList(displayList);
+ return;
+ }
+ }
+
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
+ if ((scrollX | scrollY) == 0) {
+ background.draw(canvas);
+ } else {
+ canvas.translate(scrollX, scrollY);
+ background.draw(canvas);
+ canvas.translate(-scrollX, -scrollY);
+ }
+ }
+
+ /**
+ * Set up background drawable display list properties.
+ *
+ * @param displayList Valid display list for the background drawable
+ */
+ private void setBackgroundDisplayListProperties(DisplayList displayList) {
+ displayList.setProjectBackwards((mPrivateFlags3 & PFLAG3_PROJECT_BACKGROUND) != 0);
+ displayList.setTranslationX(mScrollX);
+ displayList.setTranslationY(mScrollY);
+ }
+
+ /**
+ * Creates a new display list or updates the existing display list for the
+ * specified Drawable.
+ *
+ * @param drawable Drawable for which to create a display list
+ * @param displayList Existing display list, or {@code null}
+ * @return A valid display list for the specified drawable
+ */
+ private static DisplayList getDrawableDisplayList(Drawable drawable, DisplayList displayList) {
+ if (displayList != null && displayList.isValid()) {
+ return displayList;
+ }
+
+ if (displayList == null) {
+ displayList = DisplayList.create(drawable.getClass().getName());
+ }
+
+ final Rect bounds = drawable.getBounds();
+ final int width = bounds.width();
+ final int height = bounds.height();
+ final HardwareCanvas canvas = displayList.start(width, height);
+ drawable.draw(canvas);
+ displayList.end();
+
+ // Set up drawable properties that are view-independent.
+ displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ displayList.setClipToBounds(false);
+ return displayList;
+ }
+
+ /**
* Returns the overlay for this view, creating it if it does not yet exist.
* Adding drawables to the overlay will cause them to be displayed whenever
* the view itself is redrawn. Objects in the overlay should be actively
@@ -15245,14 +15359,22 @@
*
* @param drawable the drawable to invalidate
*/
+ @Override
public void invalidateDrawable(Drawable drawable) {
if (verifyDrawable(drawable)) {
- final Rect dirty = drawable.getBounds();
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
+ if (drawable == mBackground && mBackgroundDisplayList != null) {
+ // If we're using a background display list, we only need to
+ // invalidate the display list and notify the parent to redraw.
+ mBackgroundDisplayList.clear();
+ invalidateViewProperty(true, false);
+ } else {
+ final Rect dirty = drawable.getBounds();
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
- invalidate(dirty.left + scrollX, dirty.top + scrollY,
- dirty.right + scrollX, dirty.bottom + scrollY);
+ invalidate(dirty.left + scrollX, dirty.top + scrollY,
+ dirty.right + scrollX, dirty.bottom + scrollY);
+ }
}
}
@@ -15399,7 +15521,7 @@
* @see Drawable#setState(int[])
*/
protected void drawableStateChanged() {
- Drawable d = mBackground;
+ final Drawable d = mBackground;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
@@ -15584,7 +15706,7 @@
Drawable d= null;
if (resid != 0) {
- d = mResources.getDrawable(resid);
+ d = mContext.getDrawable(resid);
}
setBackground(d);
@@ -18754,6 +18876,35 @@
}
/**
+ * Specifies that the shared name of the View to be shared with another Activity.
+ * When transitioning between Activities, the name links a UI element in the starting
+ * Activity to UI element in the called Activity. Names should be unique in the
+ * View hierarchy.
+ *
+ * @param sharedElementName The cross-Activity View identifier. The called Activity will use
+ * the name to match the location with a View in its layout.
+ * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+ */
+ public void setSharedElementName(String sharedElementName) {
+ setTagInternal(com.android.internal.R.id.shared_element_name, sharedElementName);
+ }
+
+ /**
+ * Returns the shared name of the View to be shared with another Activity.
+ * When transitioning between Activities, the name links a UI element in the starting
+ * Activity to UI element in the called Activity. Names should be unique in the
+ * View hierarchy.
+ *
+ * <p>This returns null if the View is not a shared element or the name if it is.</p>
+ *
+ * @return The name used for this View for cross-Activity transitions or null if
+ * this View has not been identified as shared.
+ */
+ public String getSharedElementName() {
+ return (String) getTag(com.android.internal.R.id.shared_element_name);
+ }
+
+ /**
* Interface definition for a callback to be invoked when a hardware key event is
* dispatched to this view. The callback will be invoked before the key event is
* given to the view. This is only useful for hardware keyboards; a software input
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b91091f..73b108f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -360,6 +360,10 @@
*/
static final int FLAG_ISOLATED_Z_VOLUME = 0x1000000;
+ static final int FLAG_IS_TRANSITION_GROUP = 0x2000000;
+
+ static final int FLAG_IS_TRANSITION_GROUP_SET = 0x4000000;
+
/**
* Indicates which types of drawing caches are to be kept in memory.
* This field should be made private, so it is hidden from the SDK.
@@ -556,6 +560,9 @@
case R.styleable.ViewGroup_layoutMode:
setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
break;
+ case R.styleable.ViewGroup_transitionGroup:
+ setTransitionGroup(a.getBoolean(attr, false));
+ break;
}
}
@@ -2288,6 +2295,41 @@
}
/**
+ * Returns true if this ViewGroup should be considered as a single entity for removal
+ * when executing an Activity transition. If this is false, child elements will move
+ * individually during the transition.
+ * @return True if the ViewGroup should be acted on together during an Activity transition.
+ * The default value is false when the background is null and true when the background
+ * is not null.
+ * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+ */
+ public boolean isTransitionGroup() {
+ if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
+ return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
+ } else {
+ return getBackground() != null;
+ }
+ }
+
+ /**
+ * Changes whether or not this ViewGroup should be treated as a single entity during
+ * ActivityTransitions.
+ * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
+ * in Activity transitions. If false, the ViewGroup won't transition,
+ * only its children. If true, the entire ViewGroup will transition
+ * together.
+ * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+ */
+ public void setTransitionGroup(boolean isTransitionGroup) {
+ mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
+ if (isTransitionGroup) {
+ mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
+ } else {
+ mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
+ }
+ }
+
+ /**
* {@inheritDoc}
*/
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5aa46f3..ccb85a6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2592,7 +2592,7 @@
R.attr.accessibilityFocusedDrawable, value, true);
if (resolved) {
mAttachInfo.mAccessibilityFocusDrawable =
- mView.mContext.getResources().getDrawable(value.resourceId);
+ mView.mContext.getDrawable(value.resourceId);
}
}
return mAttachInfo.mAccessibilityFocusDrawable;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2f62431..11740ab 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityOptions;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -1039,7 +1040,7 @@
*/
public void setBackgroundDrawableResource(int resid)
{
- setBackgroundDrawable(mContext.getResources().getDrawable(resid));
+ setBackgroundDrawable(mContext.getDrawable(resid));
}
/**
@@ -1374,8 +1375,41 @@
/**
* Set options that can affect the transition behavior within this window.
* @param options Options to set or null for none
+ * @hide
*/
- public void setTransitionOptions(Bundle options) {
- throw new UnsupportedOperationException();
+ public void setTransitionOptions(ActivityOptions options, SceneTransitionListener listener) {
+ }
+
+ /**
+ * A callback for Activity transitions to be told when the shared element is ready to be shown
+ * and start the transition to its target location.
+ * @hide
+ */
+ public interface SceneTransitionListener {
+ void enterSharedElement(Bundle transitionArgs);
+ void nullPendingTransition();
+ void convertFromTranslucent();
+ void convertToTranslucent();
+ }
+
+ /**
+ * Controls how the background fade is triggered. If fadeEarly is true, the Window background
+ * will fade in as soon as the shared elements are ready to switch. If fadeEarly is false,
+ * the background will fade only after the calling Activity's exit transition completes.
+ * By default, the Window will fade in when the calling Activity's exit transition completes.
+ *
+ * @param fadeEarly Set to true to fade out the exiting Activity as soon as the shared elements
+ * are transferred. Set to false to fade out the exiting Activity as soon as
+ * the shared element is transferred.
+ * @hide
+ */
+ public void setEarlyBackgroundTransition(boolean fadeEarly) {
+ }
+
+ /**
+ * Start the exit transition.
+ * @hide
+ */
+ public void startExitTransition(ActivityOptions activityOptions) {
}
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4d8975c..13febe9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1604,7 +1604,7 @@
}
private void useDefaultSelector() {
- setSelector(getResources().getDrawable(
+ setSelector(getContext().getDrawable(
com.android.internal.R.drawable.list_selector_background));
}
@@ -2616,7 +2616,7 @@
* @attr ref android.R.styleable#AbsListView_listSelector
*/
public void setSelector(int resID) {
- setSelector(getResources().getDrawable(resID));
+ setSelector(getContext().getDrawable(resID));
}
public void setSelector(Drawable sel) {
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 3c88e94..5b80648 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -80,17 +80,17 @@
mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);
if (mDial == null) {
- mDial = r.getDrawable(com.android.internal.R.drawable.clock_dial);
+ mDial = context.getDrawable(com.android.internal.R.drawable.clock_dial);
}
mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour);
if (mHourHand == null) {
- mHourHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_hour);
+ mHourHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_hour);
}
mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);
if (mMinuteHand == null) {
- mMinuteHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_minute);
+ mMinuteHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_minute);
}
mCalendar = new Time();
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 34cfea5..10e56c7 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -322,7 +322,7 @@
CharSequence grpName, CharSequence description, boolean dangerous) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- Drawable icon = context.getResources().getDrawable(dangerous
+ Drawable icon = context.getDrawable(dangerous
? R.drawable.ic_bullet_key_permission : R.drawable.ic_text_dot);
return getPermissionItemViewOld(context, inflater, grpName,
description, dangerous, icon);
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 259c66b..eb232fd 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -366,7 +366,7 @@
* @attr ref android.R.styleable#PopupWindow_popupBackground
*/
public void setDropDownBackgroundResource(int id) {
- mPopup.setBackgroundDrawable(getResources().getDrawable(id));
+ mPopup.setBackgroundDrawable(getContext().getDrawable(id));
}
/**
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index c6be6dd..ea60abb 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -1029,7 +1029,7 @@
@Override
public void setSelectedDateVerticalBar(int resourceId) {
- Drawable drawable = mDelegator.getResources().getDrawable(resourceId);
+ Drawable drawable = mDelegator.getContext().getDrawable(resourceId);
setSelectedDateVerticalBar(drawable);
}
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 78b1b75..1533510 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -123,7 +123,7 @@
Drawable d = null;
if (mCheckMarkResource != 0) {
- d = getResources().getDrawable(mCheckMarkResource);
+ d = getContext().getDrawable(mCheckMarkResource);
}
setCheckMarkDrawable(d);
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index b22088c..4298545 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -186,7 +186,7 @@
Drawable d = null;
if (mButtonResource != 0) {
- d = getResources().getDrawable(mButtonResource);
+ d = getContext().getDrawable(mButtonResource);
}
setButtonDrawable(d);
}
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 30752e0..fa37443 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -136,8 +136,8 @@
*/
public EdgeEffect(Context context) {
final Resources res = context.getResources();
- mEdge = res.getDrawable(R.drawable.overscroll_edge);
- mGlow = res.getDrawable(R.drawable.overscroll_glow);
+ mEdge = context.getDrawable(R.drawable.overscroll_edge);
+ mGlow = context.getDrawable(R.drawable.overscroll_glow);
mEdgeHeight = mEdge.getIntrinsicHeight();
mGlowHeight = mGlow.getIntrinsicHeight();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 11dbce8..ea62bbe 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1679,7 +1679,7 @@
private void updateCursorPosition(int cursorIndex, int top, int bottom, float horizontal) {
if (mCursorDrawable[cursorIndex] == null)
- mCursorDrawable[cursorIndex] = mTextView.getResources().getDrawable(
+ mCursorDrawable[cursorIndex] = mTextView.getContext().getDrawable(
mTextView.mCursorDrawableRes);
if (mTempRect == null) mTempRect = new Rect();
@@ -2969,7 +2969,7 @@
positionY += mContentView.getMeasuredHeight();
// Assumes insertion and selection handles share the same height
- final Drawable handle = mTextView.getResources().getDrawable(
+ final Drawable handle = mTextView.getContext().getDrawable(
mTextView.mTextSelectHandleRes);
positionY += handle.getIntrinsicHeight();
}
@@ -3546,7 +3546,7 @@
private InsertionHandleView getHandle() {
if (mSelectHandleCenter == null) {
- mSelectHandleCenter = mTextView.getResources().getDrawable(
+ mSelectHandleCenter = mTextView.getContext().getDrawable(
mTextView.mTextSelectHandleRes);
}
if (mHandle == null) {
@@ -3592,11 +3592,11 @@
private void initDrawables() {
if (mSelectHandleLeft == null) {
- mSelectHandleLeft = mTextView.getContext().getResources().getDrawable(
+ mSelectHandleLeft = mTextView.getContext().getDrawable(
mTextView.mTextSelectHandleLeftRes);
}
if (mSelectHandleRight == null) {
- mSelectHandleRight = mTextView.getContext().getResources().getDrawable(
+ mSelectHandleRight = mTextView.getContext().getDrawable(
mTextView.mTextSelectHandleRightRes);
}
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 0f51fab..572302a 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -364,13 +364,13 @@
@android.view.RemotableViewMethod
public void setImageResource(int resId) {
if (mUri != null || mResource != resId) {
+ final int oldWidth = mDrawableWidth;
+ final int oldHeight = mDrawableHeight;
+
updateDrawable(null);
mResource = resId;
mUri = null;
- final int oldWidth = mDrawableWidth;
- final int oldHeight = mDrawableHeight;
-
resolveUri();
if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
@@ -570,7 +570,7 @@
}
/** Return the view's optional matrix. This is applied to the
- view's drawable when it is drawn. If there is not matrix,
+ view's drawable when it is drawn. If there is no matrix,
this method will return an identity matrix.
Do not change this matrix in place but make a copy.
If you want a different matrix applied to the drawable,
@@ -642,7 +642,7 @@
if (mResource != 0) {
try {
- d = rsrc.getDrawable(mResource);
+ d = mContext.getDrawable(mResource);
} catch (Exception e) {
Log.w("ImageView", "Unable to find resource: " + mResource, e);
// Don't try again.
@@ -655,7 +655,7 @@
// Load drawable through Resources, to get the source density information
ContentResolver.OpenResourceIdResult r =
mContext.getContentResolver().getResourceId(mUri);
- d = r.r.getDrawable(r.id);
+ d = r.r.getDrawable(r.id, mContext.getTheme());
} catch (Exception e) {
Log.w("ImageView", "Unable to open content: " + mUri, e);
}
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index a4f758c..74b41c9 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -155,7 +155,7 @@
*/
public void setImageToDefault() {
if (mDefaultAvatar == null) {
- mDefaultAvatar = getResources().getDrawable(R.drawable.ic_contact_picture);
+ mDefaultAvatar = mContext.getDrawable(R.drawable.ic_contact_picture);
}
setImageDrawable(mDefaultAvatar);
}
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 3791258..1eedc5d 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1059,7 +1059,7 @@
SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // for the icon
ssb.append(hintText);
- Drawable searchIcon = getContext().getResources().getDrawable(getSearchIconId());
+ Drawable searchIcon = getContext().getDrawable(getSearchIconId());
int textSize = (int) (mQueryTextView.getTextSize() * 1.25);
searchIcon.setBounds(0, 0, textSize, textSize);
ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index bdaaa01..64a1574 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -168,7 +168,7 @@
// Lookup and set the expand action icon.
TypedValue outTypedValue = new TypedValue();
mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
- Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
+ Drawable drawable = mContext.getDrawable(outTypedValue.resourceId);
activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
activityChooserView.setProvider(this);
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index eabe1a3..9601d4a 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -281,7 +281,7 @@
* @attr ref android.R.styleable#Spinner_popupBackground
*/
public void setPopupBackgroundResource(int resId) {
- setPopupBackgroundDrawable(getContext().getResources().getDrawable(resId));
+ setPopupBackgroundDrawable(getContext().getDrawable(resId));
}
/**
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index c44d431..c8917e0 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -529,7 +529,7 @@
return drawable;
}
// Not cached, find it by resource ID
- drawable = mProviderContext.getResources().getDrawable(resourceId);
+ drawable = mProviderContext.getDrawable(resourceId);
// Stick it in the cache, using the URI as key
storeInIconCache(drawableUri, drawable);
return drawable;
@@ -563,7 +563,7 @@
OpenResourceIdResult r =
mProviderContext.getContentResolver().getResourceId(uri);
try {
- return r.r.getDrawable(r.id);
+ return r.r.getDrawable(r.id, mContext.getTheme());
} catch (Resources.NotFoundException ex) {
throw new FileNotFoundException("Resource does not exist: " + uri);
}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index c9a1ca4..2a5fb15 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -417,7 +417,7 @@
* @attr ref android.R.styleable#Switch_track
*/
public void setTrackResource(int resId) {
- setTrackDrawable(getContext().getResources().getDrawable(resId));
+ setTrackDrawable(getContext().getDrawable(resId));
}
/**
@@ -453,7 +453,7 @@
* @attr ref android.R.styleable#Switch_thumb
*/
public void setThumbResource(int resId) {
- setThumbDrawable(getContext().getResources().getDrawable(resId));
+ setThumbDrawable(getContext().getDrawable(resId));
}
/**
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 568b3e6..47a5449 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -120,28 +120,27 @@
setChildrenDrawingOrderEnabled(true);
final Context context = mContext;
- final Resources resources = context.getResources();
// Tests the target Sdk version, as set in the Manifest. Could not be set using styles.xml
// in a values-v? directory which targets the current platform Sdk version instead.
if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
// Donut apps get old color scheme
if (mLeftStrip == null) {
- mLeftStrip = resources.getDrawable(
+ mLeftStrip = context.getDrawable(
com.android.internal.R.drawable.tab_bottom_left_v4);
}
if (mRightStrip == null) {
- mRightStrip = resources.getDrawable(
+ mRightStrip = context.getDrawable(
com.android.internal.R.drawable.tab_bottom_right_v4);
}
} else {
// Use modern color scheme for Eclair and beyond
if (mLeftStrip == null) {
- mLeftStrip = resources.getDrawable(
+ mLeftStrip = context.getDrawable(
com.android.internal.R.drawable.tab_bottom_left);
}
if (mRightStrip == null) {
- mRightStrip = resources.getDrawable(
+ mRightStrip = context.getDrawable(
com.android.internal.R.drawable.tab_bottom_right);
}
}
@@ -246,7 +245,7 @@
* divider.
*/
public void setDividerDrawable(int resId) {
- setDividerDrawable(getResources().getDrawable(resId));
+ setDividerDrawable(mContext.getDrawable(resId));
}
/**
@@ -267,7 +266,7 @@
* left strip drawable
*/
public void setLeftStripDrawable(int resId) {
- setLeftStripDrawable(getResources().getDrawable(resId));
+ setLeftStripDrawable(mContext.getDrawable(resId));
}
/**
@@ -288,7 +287,7 @@
* right strip drawable
*/
public void setRightStripDrawable(int resId) {
- setRightStripDrawable(getResources().getDrawable(resId));
+ setRightStripDrawable(mContext.getDrawable(resId));
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 15606a4..3be23b7 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2073,11 +2073,11 @@
*/
@android.view.RemotableViewMethod
public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) {
- final Resources resources = getContext().getResources();
- setCompoundDrawablesWithIntrinsicBounds(left != 0 ? resources.getDrawable(left) : null,
- top != 0 ? resources.getDrawable(top) : null,
- right != 0 ? resources.getDrawable(right) : null,
- bottom != 0 ? resources.getDrawable(bottom) : null);
+ final Context context = getContext();
+ setCompoundDrawablesWithIntrinsicBounds(left != 0 ? context.getDrawable(left) : null,
+ top != 0 ? context.getDrawable(top) : null,
+ right != 0 ? context.getDrawable(right) : null,
+ bottom != 0 ? context.getDrawable(bottom) : null);
}
/**
@@ -2247,12 +2247,12 @@
@android.view.RemotableViewMethod
public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end,
int bottom) {
- final Resources resources = getContext().getResources();
+ final Context context = getContext();
setCompoundDrawablesRelativeWithIntrinsicBounds(
- start != 0 ? resources.getDrawable(start) : null,
- top != 0 ? resources.getDrawable(top) : null,
- end != 0 ? resources.getDrawable(end) : null,
- bottom != 0 ? resources.getDrawable(bottom) : null);
+ start != 0 ? context.getDrawable(start) : null,
+ top != 0 ? context.getDrawable(top) : null,
+ end != 0 ? context.getDrawable(end) : null,
+ bottom != 0 ? context.getDrawable(bottom) : null);
}
/**
@@ -4385,8 +4385,8 @@
if (error == null) {
setError(null, null);
} else {
- Drawable dr = getContext().getResources().
- getDrawable(com.android.internal.R.drawable.indicator_input_error);
+ Drawable dr = getContext().getDrawable(
+ com.android.internal.R.drawable.indicator_input_error);
dr.setBounds(0, 0, dr.getIntrinsicWidth(), dr.getIntrinsicHeight());
setError(error, dr);
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 347f957..0a80495 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -1081,7 +1081,7 @@
@Override
public Tab setIcon(int resId) {
- return setIcon(mContext.getResources().getDrawable(resId));
+ return setIcon(mContext.getDrawable(resId));
}
@Override
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialog.java b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
index 8fc99c7..b0e0373 100644
--- a/core/java/com/android/internal/app/MediaRouteControllerDialog.java
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
@@ -256,13 +256,13 @@
private Drawable getIconDrawable() {
if (mRoute.isConnecting()) {
if (mMediaRouteConnectingDrawable == null) {
- mMediaRouteConnectingDrawable = getContext().getResources().getDrawable(
+ mMediaRouteConnectingDrawable = getContext().getDrawable(
R.drawable.ic_media_route_connecting_holo_dark);
}
return mMediaRouteConnectingDrawable;
} else {
if (mMediaRouteOnDrawable == null) {
- mMediaRouteOnDrawable = getContext().getResources().getDrawable(
+ mMediaRouteOnDrawable = getContext().getDrawable(
R.drawable.ic_media_route_on_holo_dark);
}
return mMediaRouteOnDrawable;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7425445..68c41fa 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -87,7 +87,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 71 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 75 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -189,9 +189,12 @@
final HistoryItem mHistoryLastWritten = new HistoryItem();
final HistoryItem mHistoryLastLastWritten = new HistoryItem();
final HistoryItem mHistoryReadTmp = new HistoryItem();
- final HashMap<String, Integer> mHistoryStringPool = new HashMap<String, Integer>();
+ final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<HistoryTag, Integer>();
String[] mReadHistoryStrings;
- int mNextHistoryStringIdx = 0;
+ int[] mReadHistoryUids;
+ int mReadHistoryChars;
+ int mNextHistoryTagIdx = 0;
+ int mNumHistoryTagChars = 0;
int mHistoryBufferLastPos = -1;
boolean mHistoryOverflow = false;
long mLastHistoryTime = 0;
@@ -1486,18 +1489,43 @@
mBtHeadset = headset;
}
+ private int writeHistoryTag(HistoryTag tag) {
+ Integer idxObj = mHistoryTagPool.get(tag);
+ int idx;
+ if (idxObj != null) {
+ idx = idxObj;
+ } else {
+ idx = mNextHistoryTagIdx;
+ HistoryTag key = new HistoryTag();
+ key.setTo(tag);
+ tag.poolIdx = idx;
+ mHistoryTagPool.put(key, idx);
+ mNextHistoryTagIdx++;
+ mNumHistoryTagChars += key.string.length() + 1;
+ }
+ return idx;
+ }
+
+ private void readHistoryTag(int index, HistoryTag tag) {
+ tag.string = mReadHistoryStrings[index];
+ tag.uid = mReadHistoryUids[index];
+ tag.poolIdx = index;
+ }
+
// Part of initial delta int that specifies the time delta.
- static final int DELTA_TIME_MASK = 0x3ffff;
- static final int DELTA_TIME_ABS = 0x3fffd; // Following is an entire abs update.
- static final int DELTA_TIME_INT = 0x3fffe; // The delta is a following int
- static final int DELTA_TIME_LONG = 0x3ffff; // The delta is a following long
+ static final int DELTA_TIME_MASK = 0x1ffff;
+ static final int DELTA_TIME_LONG = 0x1ffff; // The delta is a following long
+ static final int DELTA_TIME_INT = 0x1fffe; // The delta is a following int
+ static final int DELTA_TIME_ABS = 0x1fffd; // Following is an entire abs update.
// Part of initial delta int holding the command code.
static final int DELTA_CMD_MASK = 0x3;
- static final int DELTA_CMD_SHIFT = 18;
+ static final int DELTA_CMD_SHIFT = 17;
// Flag in delta int: a new battery level int follows.
- static final int DELTA_BATTERY_LEVEL_FLAG = 1<<20;
+ static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
// Flag in delta int: a new full state and battery status int follows.
- static final int DELTA_STATE_FLAG = 1<<21;
+ static final int DELTA_STATE_FLAG = 0x00100000;
+ // Flag in delta int: contains a wakelock tag.
+ static final int DELTA_WAKELOCK_FLAG = 0x00200000;
static final int DELTA_STATE_MASK = 0xffc00000;
public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
@@ -1532,6 +1560,9 @@
if (stateIntChanged) {
firstToken |= DELTA_STATE_FLAG;
}
+ if (cur.wakelockTag != null) {
+ firstToken |= DELTA_WAKELOCK_FLAG;
+ }
dest.writeInt(firstToken);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ " deltaTime=" + deltaTime);
@@ -1562,20 +1593,19 @@
+ " batteryPlugType=" + cur.batteryPlugType
+ " states=0x" + Integer.toHexString(cur.states));
}
+ if (cur.wakelockTag != null) {
+ int index = writeHistoryTag(cur.wakelockTag);
+ dest.writeInt(index);
+ if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+ + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
+ }
if (cur.cmd == HistoryItem.CMD_EVENT) {
- Integer idxObj = mHistoryStringPool.get(cur.eventName);
- int codeAndIndex = (cur.eventCode&0xffff);
- int idx;
- if (idxObj != null) {
- idx = idxObj;
- } else {
- idx = mNextHistoryStringIdx;
- mHistoryStringPool.put(cur.eventName, mNextHistoryStringIdx);
- mNextHistoryStringIdx++;
- }
- codeAndIndex |= (idx<<16);
+ int index = writeHistoryTag(cur.eventTag);
+ int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);
dest.writeInt(codeAndIndex);
- dest.writeInt(cur.eventUid);
+ if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#"
+ + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+ + cur.eventTag.string);
}
}
@@ -1596,6 +1626,7 @@
int firstToken = src.readInt();
int deltaTimeToken = firstToken&DELTA_TIME_MASK;
cur.cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK);
+ cur.numReadInts = 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ " deltaTimeToken=" + deltaTimeToken);
@@ -1603,16 +1634,20 @@
cur.time += deltaTimeToken;
} else if (deltaTimeToken == DELTA_TIME_ABS) {
cur.time = src.readLong();
+ cur.numReadInts += 2;
+ if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
cur.readFromParcel(src);
return;
} else if (deltaTimeToken == DELTA_TIME_INT) {
int delta = src.readInt();
cur.time += delta;
+ cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
} else {
long delta = src.readLong();
if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
cur.time += delta;
+ cur.numReadInts += 2;
}
if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
@@ -1620,6 +1655,7 @@
cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f);
cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21);
cur.batteryVoltage = (char)(batteryLevelInt&0x3fff);
+ cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x"
+ Integer.toHexString(batteryLevelInt)
+ " batteryLevel=" + cur.batteryLevel
@@ -1633,6 +1669,7 @@
cur.batteryStatus = (byte)((stateInt>>28)&0xf);
cur.batteryHealth = (byte)((stateInt>>24)&0xf);
cur.batteryPlugType = (byte)((stateInt>>22)&0x3);
+ cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
+ Integer.toHexString(stateInt)
+ " batteryStatus=" + cur.batteryStatus
@@ -1643,55 +1680,78 @@
cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~DELTA_STATE_MASK));
}
+ if ((firstToken&DELTA_WAKELOCK_FLAG) != 0) {
+ cur.wakelockTag = cur.localWakelockTag;
+ int index = src.readInt();
+ readHistoryTag(index, cur.wakelockTag);
+ cur.numReadInts += 1;
+ if (DEBUG) Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+ + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
+ } else {
+ cur.wakelockTag = null;
+ }
+
if (cur.cmd == HistoryItem.CMD_EVENT) {
- int codeAndIndex = src.readInt();
+ cur.eventTag = cur.localEventTag;
+ final int codeAndIndex = src.readInt();
cur.eventCode = (codeAndIndex&0xffff);
- int index = ((codeAndIndex>>16)&0xffff);
- cur.eventName = mReadHistoryStrings[index];
- cur.eventNameIdx = index;
- cur.eventUid = src.readInt();
+ final int index = ((codeAndIndex>>16)&0xffff);
+ readHistoryTag(index, cur.eventTag);
+ cur.numReadInts += 1;
+ if (DEBUG) Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#"
+ + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+ + cur.eventTag.string);
} else {
cur.eventCode = HistoryItem.EVENT_NONE;
}
}
- int mChangedBufferStates = 0;
-
void addHistoryBufferLocked(long curTime) {
if (!mHaveBatteryLevel || !mRecordingHistory) {
return;
}
final long timeDiff = (mHistoryBaseTime+curTime) - mHistoryLastWritten.time;
+ final int diffStates = mHistoryLastWritten.states^mHistoryCur.states;
+ final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states;
+ if (DEBUG) Slog.i(TAG, "ADD: tdelta=" + timeDiff + " diff="
+ + Integer.toHexString(diffStates) + " lastDiff="
+ + Integer.toHexString(lastDiffStates));
if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
- && timeDiff < 2000
- && ((mHistoryLastWritten.states^mHistoryCur.states)&mChangedBufferStates) == 0) {
- // If the current is the same as the one before, then we no
- // longer need the entry.
+ && timeDiff < 1000 && (diffStates&lastDiffStates) == 0
+ && (mHistoryLastWritten.wakelockTag == null || mHistoryCur.wakelockTag == null)
+ && mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel
+ && mHistoryLastWritten.batteryStatus == mHistoryCur.batteryStatus
+ && mHistoryLastWritten.batteryHealth == mHistoryCur.batteryHealth
+ && mHistoryLastWritten.batteryPlugType == mHistoryCur.batteryPlugType
+ && mHistoryLastWritten.batteryTemperature == mHistoryCur.batteryTemperature
+ && mHistoryLastWritten.batteryVoltage == mHistoryCur.batteryVoltage) {
+ // We can merge this new change in with the last one. Merging is
+ // allows as long as only the states have changed, and within those states
+ // as long as no bit has changed both between now and the last entry, as
+ // well as the last entry and the one before it (so we capture any toggles).
+ if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos);
mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
mHistoryBufferLastPos = -1;
- if (mHistoryLastLastWritten.cmd == HistoryItem.CMD_UPDATE
- && timeDiff < 500 && mHistoryLastLastWritten.sameNonEvent(mHistoryCur)) {
- // If this results in us returning to the state written
- // prior to the last one, then we can just delete the last
- // written one and drop the new one. Nothing more to do.
- mHistoryLastWritten.setTo(mHistoryLastLastWritten);
- mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
- return;
- }
- mChangedBufferStates |= mHistoryLastWritten.states^mHistoryCur.states;
curTime = mHistoryLastWritten.time - mHistoryBaseTime;
+ // If the last written history had a wakelock tag, we need to retain it.
+ // Note that the condition above made sure that we aren't in a case where
+ // both it and the current history item have a wakelock tag.
+ if (mHistoryLastWritten.wakelockTag != null) {
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
+ }
mHistoryLastWritten.setTo(mHistoryLastLastWritten);
- } else {
- mChangedBufferStates = 0;
}
final int dataSize = mHistoryBuffer.dataSize();
if (dataSize >= MAX_HISTORY_BUFFER) {
if (!mHistoryOverflow) {
mHistoryOverflow = true;
+ addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
addHistoryBufferLocked(curTime, HistoryItem.CMD_OVERFLOW);
+ return;
}
// Once we've reached the maximum number of items, we only
@@ -1704,6 +1764,9 @@
& HistoryItem.MOST_INTERESTING_STATES) == 0)) {
return;
}
+
+ addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
+ return;
}
addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
@@ -1719,10 +1782,8 @@
private void addHistoryBufferLocked(long curTime, byte cmd,
int eventCode, String eventName, int eventUid) {
- int origPos = 0;
if (mIteratingHistory) {
- origPos = mHistoryBuffer.dataPosition();
- mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+ throw new IllegalStateException("Can't do this while iterating history!");
}
mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
mHistoryLastLastWritten.setTo(mHistoryLastWritten);
@@ -1730,12 +1791,10 @@
eventCode, eventUid, eventName, mHistoryCur);
writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
mLastHistoryTime = curTime;
+ mHistoryCur.wakelockTag = null;
if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
+ " now " + mHistoryBuffer.dataPosition()
+ " size is now " + mHistoryBuffer.dataSize());
- if (mIteratingHistory) {
- mHistoryBuffer.setDataPosition(origPos);
- }
}
int mChangedStates = 0;
@@ -1845,11 +1904,12 @@
mHistoryBuffer.setDataSize(0);
mHistoryBuffer.setDataPosition(0);
- mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2);
+ mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2);
mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
- mHistoryStringPool.clear();
- mNextHistoryStringIdx = 0;
+ mHistoryTagPool.clear();
+ mNextHistoryTagIdx = 0;
+ mNumHistoryTagChars = 0;
mHistoryBufferLastPos = -1;
mHistoryOverflow = false;
}
@@ -1914,6 +1974,9 @@
mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = name;
+ mHistoryCur.wakelockTag.uid = uid;
addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
mWakeLockNesting++;
@@ -2161,7 +2224,7 @@
// Fake a wake lock, so we consider the device waked as long
// as the screen is on.
- noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
+ noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);
// Update discharge amounts.
if (mOnBatteryInternal) {
@@ -4854,11 +4917,14 @@
public boolean startIteratingOldHistoryLocked() {
if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
+ " pos=" + mHistoryBuffer.dataPosition());
+ if ((mHistoryIterator = mHistory) == null) {
+ return false;
+ }
mHistoryBuffer.setDataPosition(0);
mHistoryReadTmp.clear();
mReadOverflow = false;
mIteratingHistory = true;
- return (mHistoryIterator = mHistory) != null;
+ return true;
}
@Override
@@ -4898,6 +4964,15 @@
public void finishIteratingOldHistoryLocked() {
mIteratingHistory = false;
mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+ mHistoryIterator = null;
+ }
+
+ public int getHistoryTotalSize() {
+ return MAX_HISTORY_BUFFER;
+ }
+
+ public int getHistoryUsedSize() {
+ return mHistoryBuffer.dataSize();
}
@Override
@@ -4907,9 +4982,15 @@
mHistoryBuffer.setDataPosition(0);
mReadOverflow = false;
mIteratingHistory = true;
- mReadHistoryStrings = new String[mHistoryStringPool.size()];
- for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) {
- mReadHistoryStrings[ent.getValue()] = ent.getKey();
+ mReadHistoryStrings = new String[mHistoryTagPool.size()];
+ mReadHistoryUids = new int[mHistoryTagPool.size()];
+ mReadHistoryChars = 0;
+ for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
+ final HistoryTag tag = ent.getKey();
+ final int idx = ent.getValue();
+ mReadHistoryStrings[idx] = tag.string;
+ mReadHistoryUids[idx] = tag.uid;
+ mReadHistoryChars += tag.string.length() + 1;
}
return mHistoryBuffer.dataSize() > 0;
}
@@ -4920,11 +5001,23 @@
}
@Override
- public String getHistoryStringPoolItem(int index) {
+ public int getHistoryStringPoolBytes() {
+ // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
+ // Each string character is 2 bytes.
+ return (mReadHistoryStrings.length * 12) + (mReadHistoryChars * 2);
+ }
+
+ @Override
+ public String getHistoryTagPoolString(int index) {
return mReadHistoryStrings[index];
}
@Override
+ public int getHistoryTagPoolUid(int index) {
+ return mReadHistoryUids[index];
+ }
+
+ @Override
public boolean getNextHistoryLocked(HistoryItem out) {
final int pos = mHistoryBuffer.dataPosition();
if (pos == 0) {
@@ -5717,17 +5810,24 @@
mHistoryBuffer.setDataSize(0);
mHistoryBuffer.setDataPosition(0);
- mHistoryStringPool.clear();
- mNextHistoryStringIdx = 0;
+ mHistoryTagPool.clear();
+ mNextHistoryTagIdx = 0;
+ mNumHistoryTagChars = 0;
- int numStrings = in.readInt();
- for (int i=0; i<numStrings; i++) {
- String str = in.readString();
+ int numTags = in.readInt();
+ for (int i=0; i<numTags; i++) {
int idx = in.readInt();
- mHistoryStringPool.put(str, idx);
- if (idx >= mNextHistoryStringIdx) {
- mNextHistoryStringIdx = idx+1;
+ String str = in.readString();
+ int uid = in.readInt();
+ HistoryTag tag = new HistoryTag();
+ tag.string = str;
+ tag.uid = uid;
+ tag.poolIdx = idx;
+ mHistoryTagPool.put(tag, idx);
+ if (idx >= mNextHistoryTagIdx) {
+ mNextHistoryTagIdx = idx+1;
}
+ mNumHistoryTagChars += tag.string.length() + 1;
}
int bufSize = in.readInt();
@@ -5797,10 +5897,12 @@
Slog.i(TAG, sb.toString());
}
out.writeLong(mHistoryBaseTime + mLastHistoryTime);
- out.writeInt(mHistoryStringPool.size());
- for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) {
- out.writeString(ent.getKey());
+ out.writeInt(mHistoryTagPool.size());
+ for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
+ HistoryTag tag = ent.getKey();
out.writeInt(ent.getValue());
+ out.writeString(tag.string);
+ out.writeInt(tag.uid);
}
out.writeInt(mHistoryBuffer.dataSize());
if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index 7ca6c1b..ed676bb 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -163,7 +163,7 @@
public MenuItem setIcon(int iconRes) {
mIconResId = iconRes;
- mIconDrawable = mContext.getResources().getDrawable(iconRes);
+ mIconDrawable = mContext.getDrawable(iconRes);
return this;
}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index b7cb0de..b776226 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -1121,7 +1121,7 @@
}
if (iconRes > 0) {
- mHeaderIcon = r.getDrawable(iconRes);
+ mHeaderIcon = getContext().getDrawable(iconRes);
} else if (icon != null) {
mHeaderIcon = icon;
}
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 4d0a326..61dcaca 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -385,7 +385,7 @@
}
if (mIconResId != NO_ICON) {
- Drawable icon = mMenu.getResources().getDrawable(mIconResId);
+ Drawable icon = mMenu.getContext().getDrawable(mIconResId);
mIconResId = NO_ICON;
mIconDrawable = icon;
return icon;
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index ff2c625..1273c4d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -697,7 +697,7 @@
}
public void setIcon(int resId) {
- setIcon(resId != 0 ? mContext.getResources().getDrawable(resId) : null);
+ setIcon(resId != 0 ? mContext.getDrawable(resId) : null);
}
public boolean hasIcon() {
@@ -712,7 +712,7 @@
}
public void setLogo(int resId) {
- setLogo(resId != 0 ? mContext.getResources().getDrawable(resId) : null);
+ setLogo(resId != 0 ? mContext.getDrawable(resId) : null);
}
public boolean hasLogo() {
@@ -1417,7 +1417,7 @@
public void setUpIndicator(int resId) {
mUpIndicatorRes = resId;
- mUpView.setImageDrawable(resId != 0 ? getResources().getDrawable(resId) : null);
+ mUpView.setImageDrawable(resId != 0 ? getContext().getDrawable(resId) : null);
}
@Override
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboard.java b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
index 8368136..7483e75 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
@@ -72,8 +72,8 @@
private void init(Context context) {
final Resources res = context.getResources();
- mShiftIcon = res.getDrawable(R.drawable.sym_keyboard_shift);
- mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked);
+ mShiftIcon = context.getDrawable(R.drawable.sym_keyboard_shift);
+ mShiftLockIcon = context.getDrawable(R.drawable.sym_keyboard_shift_locked);
sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
R.dimen.password_keyboard_spacebar_vertical_correction);
}
diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
index cd1ccd3..93ea5b3 100644
--- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
@@ -234,7 +234,7 @@
mMagneticTargets = a.getBoolean(R.styleable.GlowPadView_magneticTargets, mMagneticTargets);
int pointId = getResourceId(a, R.styleable.GlowPadView_pointDrawable);
- Drawable pointDrawable = pointId != 0 ? res.getDrawable(pointId) : null;
+ Drawable pointDrawable = pointId != 0 ? context.getDrawable(pointId) : null;
mGlowRadius = a.getDimension(R.styleable.GlowPadView_glowRadius, 0.0f);
TypedValue outValue = new TypedValue();
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 3116955..5d49204 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -141,7 +141,8 @@
*needsDetach = false;
JNIEnv* env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
- JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
+ JavaVMAttachArgs args = {
+ JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL };
JavaVM* vm = AndroidRuntime::getJavaVM();
int result = vm->AttachCurrentThread(&env, (void*) &args);
if (result != JNI_OK) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b7a06b5..7ea08af 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -583,7 +583,7 @@
<!-- =============================================================== -->
<eat-comment />
- <!-- Used for permissions that provide access to the user voicemail box. -->
+ <!-- Used for permissions that provide access to device alarms. -->
<permission-group android:name="android.permission-group.DEVICE_ALARMS"
android:label="@string/permgrouplab_deviceAlarms"
android:icon="@drawable/perm_group_device_alarms"
@@ -1061,7 +1061,7 @@
<!-- =========================================== -->
<eat-comment />
- <!-- Used for permissions that are associated with accessing and modifyign
+ <!-- Used for permissions that are associated with accessing and modifying
telephony state: placing calls, intercepting outgoing calls, reading
and modifying the phone state. -->
<permission-group android:name="android.permission-group.PHONE_CALLS"
@@ -1727,6 +1727,13 @@
android:label="@string/permlab_recovery"
android:description="@string/permdesc_recovery" />
+ <!-- Allows the system to bind to an application's idle services
+ @hide -->
+ <permission android:name="android.permission.BIND_IDLE_SERVICE"
+ android:protectionLevel="signature"
+ android:label="@string/permlab_bindIdleService"
+ android:description="@string/permdesc_bindIdleService" />
+
<!-- ========================================= -->
<!-- Permissions for special development tools -->
<!-- ========================================= -->
@@ -2728,6 +2735,14 @@
</intent-filter>
</service>
+ <service android:name="com.android.server.MountServiceIdler"
+ android:exported="false"
+ android:permission="android.permission.BIND_IDLE_SERVICE" >
+ <intent-filter>
+ <action android:name="android.service.idle.IdleService" />
+ </intent-filter>
+ </service>
+
</application>
</manifest>
diff --git a/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..8d529b8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_search_api_holo_light.png b/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
index 72e207b..8b15ecb 100644
--- a/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..32062a6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
index 3481c98..d2b2d21 100644
--- a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search.png b/core/res/res/drawable-mdpi/ic_search.png
index 4be72f1..66145e0 100644
--- a/core/res/res/drawable-mdpi/ic_search.png
+++ b/core/res/res/drawable-mdpi/ic_search.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..4771a56
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_api_holo_light.png b/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
index f2e26f8..60a55f8 100644
--- a/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search.png b/core/res/res/drawable-mdpi/ic_voice_search.png
index 73c6be6..b2535fb 100644
--- a/core/res/res/drawable-mdpi/ic_voice_search.png
+++ b/core/res/res/drawable-mdpi/ic_voice_search.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..fcc2105
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
index 71d838e..b516b95 100644
--- a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search.png b/core/res/res/drawable-xhdpi/ic_search.png
index 998f91b..738a392 100644
--- a/core/res/res/drawable-xhdpi/ic_search.png
+++ b/core/res/res/drawable-xhdpi/ic_search.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..b0d7acf
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png b/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
index a4cdf1c..c9626a0 100644
--- a/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_category_default.png b/core/res/res/drawable-xhdpi/ic_search_category_default.png
index 7d5170e..351cfe0 100644
--- a/core/res/res/drawable-xhdpi/ic_search_category_default.png
+++ b/core/res/res/drawable-xhdpi/ic_search_category_default.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search.png b/core/res/res/drawable-xhdpi/ic_voice_search.png
index c625a36..3f0518b 100644
--- a/core/res/res/drawable-xhdpi/ic_voice_search.png
+++ b/core/res/res/drawable-xhdpi/ic_voice_search.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..eb6e5fa
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
index c332ba0..c6b40bb 100644
--- a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..eb30465
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png b/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png
new file mode 100644
index 0000000..bc14415
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..813048c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png
new file mode 100644
index 0000000..8addde0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0643e3b..8eadf2c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1526,7 +1526,7 @@
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"S\'està desbloquejant la targeta SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Codi PIN incorrecte."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escriu un PIN que tingui de 4 a 8 números."</string>
- <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"El codi PUK ha de contenir 8 números."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"El codi PUK ha de tenir 8 números."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM de manera permanent."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Els codis PIN no coincideixen"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Massa intents incorrectes"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 85efbf6..1a5228d 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1526,8 +1526,7 @@
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ապակողպում է SIM քարտը ..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Սխալ PIN ծածկագիր:"</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Մուտքագրեք PIN, որը 4-ից 8 թիվ է:"</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK կոդը պետք է լինի 8 թիվ:"</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"Վերամուտքագրեք ճիշտ PUK ծածկագիրը: Կրկնվող փորձերը ընդմիշտ կկասեցնեն SIM քարտը:"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN ծածկագրերը չեն համընկնում"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Չափից շատ սխեմայի փորձեր"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index eb03857..38d518a 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1200,7 +1200,7 @@
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិនអាចតភ្ជាប់វ៉ាយហ្វាយ"</string>
<string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" មានការតភ្ជាប់អ៊ីនធឺណិតមិនល្អ។"</string>
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"វ៉ាយហ្វាយផ្ទាល់"</string>
- <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ចាប់ផ្ដើមវ៉ាយហ្វាយដោយផ្ទាល់។ វានឹងបិទវ៉ាយហ្វាយ ។"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ចាប់ផ្ដើមវ៉ាយហ្វាយផ្ទាល់។ វានឹងបិទវ៉ាយហ្វាយហតស្ពត។"</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"មិនអាចចាប់ផ្ដើមវ៉ាយហ្វាដោយផ្ទាល់។"</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"បើកវ៉ាយហ្វាយផ្ទាល់"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"ប៉ះ ដើម្បីកំណត់"</string>
@@ -1357,7 +1357,7 @@
<string name="submit" msgid="1602335572089911941">"ដាក់ស្នើ"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"បានបើករបៀបរថយន្ត"</string>
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"ប៉ះ ដើម្បីចេញពីរបៀបរថយន្ត។"</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"ភ្ជាប់ ឬ hotspot សកម្ម"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ភ្ជាប់ ឬហតស្ពតសកម្ម"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"ប៉ះ ដើម្បីរៀបចំ។"</string>
<string name="back_button_label" msgid="2300470004503343439">"ថយក្រោយ"</string>
<string name="next_button_label" msgid="1080555104677992408">"បន្ទាប់"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 62cdcaf..f9d005d 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1526,8 +1526,7 @@
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kad SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Kod PUK mestilah 8 nombor."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4d6f459..b222103 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1526,8 +1526,7 @@
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
- <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
- <skip />
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Codul PUK trebuie să conțină 8 numere."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 01e1255..d0fcc09 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1526,7 +1526,7 @@
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Inafungua SIM kadi..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Msimbo wa PIN usio sahihi."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Charaza PIN iliyo na tarakimu kati ya 4 na 8."</string>
- <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Msimbo wa PUK lazima uwe na nambari 8."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Msimbo wa PUK lazima uwe na tarakimu 8."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yanayorudiwa yatalemaza SIM kabisa."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Misimbo ya PIN haifanani"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ca9c8bd..9526e13 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2244,6 +2244,17 @@
Hence, the TextView is a label for the EditText. -->
<attr name="labelFor" format="integer" />
+ <!-- Specifies a theme override for a view. When a theme override is set, the
+ view will be inflated using a {@link android.content.Context} themed with
+ the specified resource. During XML inflation, any child views under the
+ view with a theme override will inherit the themed context. -->
+ <attr name="theme" />
+
+ <!-- Specifies that the shared name of the View to be shared with another Activity.
+ When transitioning between Activities, the name links a UI element in the starting
+ Activity to UI element in the called Activity. Names should be unique in the
+ View hierarchy. -->
+ <attr name="sharedElementName" format="string" />
</declare-styleable>
<!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -2330,6 +2341,14 @@
<!-- Use the children's optical bounds when laying out this container. -->
<enum name="opticalBounds" value="1" />
</attr>
+
+ <!-- Sets whether or not this ViewGroup should be treated as a single entity
+ when doing an Activity transition. Typically, the elements inside a
+ ViewGroup are each transitioned from the scene individually. The default
+ for a ViewGroup is false unless it has a background.
+ See {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)}
+ for more information. -->
+ <attr name="transitionGroup" format="boolean" />
</declare-styleable>
<!-- A {@link android.view.ViewStub} lets you lazily include other XML layouts
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 5c0baaa..56bb15f 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -82,4 +82,5 @@
<item type="id" name="action_bar_spinner" />
<item type="id" name="current_scene" />
<item type="id" name="scene_layoutid_cache" />
+ <item type="id" name="shared_element_name" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e99b5ba..722f965 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2104,6 +2104,12 @@
<public type="attr" name="controlY1" />
<public type="attr" name="controlX2" />
<public type="attr" name="controlY2" />
+ <public type="attr" name="fromSceneName" />
+ <public type="attr" name="toSceneName" />
+ <public type="attr" name="sharedElementName" />
+ <public type="attr" name="transitionGroup" />
+
+ <public type="id" name="shared_element_name" />
<public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
<public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 785e788..ee68199 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1176,6 +1176,11 @@
<string name="permdesc_manageCaCertificates">Allows the app to install and uninstall CA certificates as trusted credentials.</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_bindIdleService">bind to idle services</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_bindIdleService">Allows the app to interact with application-defined idle services.</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_diagnostic">read/write to resources owned by diag</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_diagnostic">Allows the app to read and write to
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 76fbded..7a654e6 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -363,7 +363,7 @@
<item name="searchViewTextField">@drawable/textfield_searchview_holo_dark</item>
<item name="searchViewTextFieldRight">@drawable/textfield_searchview_right_holo_dark</item>
<item name="searchViewCloseIcon">@android:drawable/ic_clear</item>
- <item name="searchViewSearchIcon">@android:drawable/ic_search</item>
+ <item name="searchViewSearchIcon">@android:drawable/ic_search_api_holo_dark</item>
<item name="searchViewGoIcon">@android:drawable/ic_go</item>
<item name="searchViewVoiceIcon">@android:drawable/ic_voice_search</item>
<item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_holo_dark</item>
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 7b9b3fb..bcd4607 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -61,7 +61,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 8, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 4, 2014.
<br/>Any versions with less than 0.1% distribution are not shown.</em>
</p>
@@ -92,7 +92,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 8, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 4, 2014.
<br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
@@ -133,17 +133,17 @@
</tr>
<tr>
<td>2.0</th>
-<td>93.5%</td>
+<td>92.3%</td>
</tr>
<tr>
<td>3.0</th>
-<td>6.4%</td>
+<td>7.6%</td>
</tr>
</table>
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 8, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 4, 2014</em></p>
@@ -161,7 +161,7 @@
var VERSION_DATA =
[
{
- "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chf=bg%2Cs%2C00000000&chd=t%3A1.3%2C21.2%2C0.1%2C16.9%2C59.1%2C1.4&chco=c4df9b%2C6fad0c&chs=500x250&cht=p",
+ "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chf=bg%2Cs%2C00000000&chd=t%3A1.3%2C20.0%2C0.1%2C16.1%2C60.7%2C1.8&chco=c4df9b%2C6fad0c",
"data": [
{
"api": 8,
@@ -171,7 +171,7 @@
{
"api": 10,
"name": "Gingerbread",
- "perc": "21.2"
+ "perc": "20.0"
},
{
"api": 13,
@@ -181,27 +181,27 @@
{
"api": 15,
"name": "Ice Cream Sandwich",
- "perc": "16.9"
+ "perc": "16.1"
},
{
"api": 16,
"name": "Jelly Bean",
- "perc": "35.9"
+ "perc": "35.5"
},
{
"api": 17,
"name": "Jelly Bean",
- "perc": "15.4"
+ "perc": "16.3"
},
{
"api": 18,
"name": "Jelly Bean",
- "perc": "7.8"
+ "perc": "8.9"
},
{
"api": 19,
"name": "KitKat",
- "perc": "1.4"
+ "perc": "1.8"
}
]
}
@@ -217,30 +217,30 @@
"data": {
"Large": {
"hdpi": "0.6",
- "ldpi": "0.9",
- "mdpi": "4.5",
- "tvdpi": "1.7",
- "xhdpi": "0.7"
+ "ldpi": "0.8",
+ "mdpi": "4.4",
+ "tvdpi": "1.6",
+ "xhdpi": "0.6"
},
"Normal": {
- "hdpi": "33.0",
+ "hdpi": "33.3",
"ldpi": "0.1",
- "mdpi": "14.2",
- "xhdpi": "20.1",
- "xxhdpi": "10.6"
+ "mdpi": "13.9",
+ "xhdpi": "20.2",
+ "xxhdpi": "11.3"
},
"Small": {
- "ldpi": "8.2"
+ "ldpi": "8.1"
},
"Xlarge": {
- "hdpi": "0.4",
+ "hdpi": "0.3",
"ldpi": "0.1",
- "mdpi": "4.7",
+ "mdpi": "4.5",
"xhdpi": "0.2"
}
},
- "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chf=bg%2Cs%2C00000000&chd=t%3A9.4%2C23.5%2C1.7%2C34.0%2C21.0%2C10.6&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
- "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chf=bg%2Cs%2C00000000&chd=t%3A5.4%2C8.5%2C78.0%2C8.2&chco=c4df9b%2C6fad0c&chs=400x250&cht=p"
+ "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chf=bg%2Cs%2C00000000&chd=t%3A9.1%2C22.8%2C1.6%2C34.3%2C21.0%2C11.3&chco=c4df9b%2C6fad0c",
+ "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=Xlarge%7CLarge%7CNormal%7CSmall&chf=bg%2Cs%2C00000000&chd=t%3A5.1%2C8.0%2C78.9%2C8.1&chco=c4df9b%2C6fad0c"
}
];
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index bf7fbe2..fb5daf8 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -92,7 +92,10 @@
<p><b>Using Android Studio:</b></p>
<ol>
- <li>Open the <code>build.gradle</code> file inside your application directory.</li>
+ <li>Open the <code>build.gradle</code> file inside your application module directory.
+ <p class="note"><strong>Note:</strong> Android Studio projects contain a top-level
+ <code>build.gradle</code> file and a <code>build.gradle</code> file for each module.
+ Be sure to edit the file for your application module.</p></li>
<li>Add a new build rule under <code>dependencies</code> for the latest version of
<code>play-services</code>. For example:
<pre class="no-pretty-print">
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index c62510b..297a2dc 100644
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -56,7 +56,9 @@
RenderScript kernel language used in this script. Currently, 1 is the only valid value.</li>
<li>A pragma declaration (<code>#pragma rs java_package_name(com.example.app)</code>) that
-declares the package name of the Java classes reflected from this script.</li>
+declares the package name of the Java classes reflected from this script.
+Note that your .rs file must be part of your application package, and not in a
+library project.</li>
<li>Some number of invokable functions. An invokable function is a single-threaded RenderScript
function that you can call from your Java code with arbitrary arguments. These are often useful for
@@ -308,4 +310,4 @@
<li><strong>Tear down the RenderScript context.</strong> The RenderScript context can be destroyed
with {@link android.renderscript.RenderScript#destroy} or by allowing the RenderScript context
object to be garbage collected. This will cause any further use of any object belonging to that
-context to throw an exception.</li> </ol>
\ No newline at end of file
+context to throw an exception.</li> </ol>
diff --git a/docs/html/tools/help/adb.jd b/docs/html/tools/help/adb.jd
index 1850123..f980042 100644
--- a/docs/html/tools/help/adb.jd
+++ b/docs/html/tools/help/adb.jd
@@ -27,6 +27,7 @@
</li>
<li><a href="#logcat">Enabling logcat logging</a></li>
<li><a href="#stopping">Stopping the adb server</a></li>
+ <li><a href="#wireless">Wireless usage</a></li>
</ol>
</div>
@@ -1342,3 +1343,100 @@
You can then restart the server by issuing any other adb command. </p>
+<h2 id="wireless">Wireless usage</h2>
+
+<p>
+adb is usually used over USB. However, it is also possible to use over
+Wi-Fi, as described here.
+</p>
+
+<ol>
+
+<li>
+Connect Android device and adb host computer
+to a common Wi-Fi network accessible to both.
+We have found that not all access points
+are suitable; you may need to use an access point
+whose firewall is configured properly to support adb.
+</li>
+
+<li>
+Connect the device with USB cable to host.
+</li>
+
+<li>
+Make sure adb is running in USB mode on host.
+<pre>
+$ adb usb
+restarting in USB mode
+</pre>
+</li>
+
+<li>
+Connect to the device over USB.
+<pre>
+$ adb devices
+List of devices attached
+######## device
+</pre>
+</li>
+
+<li>
+Restart host adb in tcpip mode.
+<pre>
+$ adb tcpip 5555
+restarting in TCP mode port: 5555
+</pre>
+</li>
+
+<li>
+Find out the IP address of the Android device:
+Settings -> About tablet -> Status -> IP address.
+Remember the IP address, of the form <code>#.#.#.#</code>.
+</li>
+
+<li>
+Connect adb host to device:
+<pre>
+$ adb connect #.#.#.#
+connected to #.#.#.#:5555
+</pre>
+</li>
+
+<li>
+Remove USB cable from device, and confirm you can still access device:
+<pre>
+$ adb devices
+List of devices attached
+#.#.#.#:5555 device
+</pre>
+
+</ol>
+
+<p>
+You're now good to go!
+</p>
+
+<p>
+If the adb connection is ever lost:
+</p>
+
+<ol>
+
+<li>
+Make sure that your host is still connected to the same Wi-Fi network your Android device is.
+</li>
+
+<li>
+Reconnect by executing the "adb connect" step again.
+</li>
+
+<li>
+Or if that doesn't work, reset your adb host:
+<pre>
+adb kill-server
+</pre>
+and then start over from the beginning.
+</li>
+
+</ol>
diff --git a/docs/html/tools/samples/index.jd b/docs/html/tools/samples/index.jd
deleted file mode 100644
index a0d11e9..0000000
--- a/docs/html/tools/samples/index.jd
+++ /dev/null
@@ -1,32 +0,0 @@
-page.title=Samples
-page.tags=example,code
-@jd:body
-
-<p>To help you understand some fundamental Android APIs and coding practices, a variety of sample
-code is available from the Android SDK Manager. Each version of the Android platform available
-from the SDK Manager offers its own set of sample apps.</p>
-
-<p>To download the samples:</p>
-<ol>
- <li>Launch the Android SDK Manager.
- <ul>
- <li>On Windows, double-click the SDK Manager.exe file at the root of the Android SDK
-directory.</li>
- <li>On Mac or Linux, open a terminal to the {@code tools/} directory in the
-Android SDK, then execute {@code android sdk}.</ul>
- </li>
- <li>Expand the list of packages for the latest Android platform.</li>
- <li>Select and download <em>Samples for SDK</em>.</li>
-</ol>
-
-<p>When the download is complete, you can find the source code for all samples at this location:</p>
-
-<p style="margin-left:2em">
-<code><sdk>/samples/android-<version>/</code>
-</p>
-
-<p>The {@code <version>} number corresponds to the platform's
- <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level</a>.</p>
-
-<p>You can easily create new Android projects with the downloaded samples, modify them
-if you'd like, and then run them on an emulator or device.</p>
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 3e6b6d4..a8424e6 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -240,12 +240,6 @@
<li class="nav-section">
- <div class="nav-section-header empty"><a href="<?cs var:toroot
-?>tools/samples/index.html"><span class="en">Samples</span></a></div>
- </li>
-
-
- <li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>tools/adk/index.html">
<span class="en">ADK</span></a>
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 52e5b5b..9360558 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -456,7 +456,7 @@
}
@Override
- protected void onDraw(Canvas canvas) {
+ public void draw(Canvas canvas) {
Bitmap bitmap = mBitmap;
if (bitmap != null) {
final BitmapState state = mBitmapState;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 2ec4284..b8365aa 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -39,9 +39,6 @@
import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
-import android.view.DisplayList;
-import android.view.HardwareCanvas;
-import android.view.HardwareRenderer;
import android.view.View;
import java.io.IOException;
@@ -142,96 +139,16 @@
private Rect mBounds = ZERO_BOUNDS_RECT; // lazily becomes a new Rect()
private WeakReference<Callback> mCallback = null;
private boolean mVisible = true;
- private DisplayList mDisplayList;
private int mLayoutDirection;
/**
* Draw in its bounds (set via setBounds) respecting optional effects such
* as alpha (set via setAlpha) and color filter (set via setColorFilter).
- * <p>
- * Overriding this method will prevent caching optimizations. To enable
- * optimizations, override {@link #onDraw} instead.
*
* @param canvas The canvas to draw into
*/
- public void draw(Canvas canvas) {
- if (canvas != null && canvas.isHardwareAccelerated() && false) { // temporarily disabled
- final HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
- final DisplayList displayList = getDisplayList(hardwareCanvas);
- if (displayList != null) {
- final int restoreCount = hardwareCanvas.save(Canvas.MATRIX_SAVE_FLAG);
- hardwareCanvas.translate(mBounds.left, mBounds.top);
- hardwareCanvas.drawDisplayList(displayList);
- hardwareCanvas.restoreToCount(restoreCount);
- return;
- }
- }
-
- onDraw(canvas);
- }
-
- /**
- * Draw in its bounds (set via setBounds) respecting optional effects such
- * as alpha (set via setAlpha) and color filter (set via setColorFilter).
- * <p>
- * Overriding this method, rather than {@link #draw}, enables caching
- * optimizations that avoid re-drawing when unnecessary.
- *
- * @param canvas The canvas to draw into
- */
- protected void onDraw(Canvas canvas) {
- throw new UnsupportedOperationException(
- "Drawable subclasses must implement either draw or onDraw");
- }
-
- /**
- * Gets a display list that can be used to draw this drawable again without
- * invoking its draw method.
- *
- * @param hardwareCanvas The hardware canvas.
- * @return A DisplayList ready to replay, or null if caching is not enabled.
- * @hide
- */
- private DisplayList getDisplayList(HardwareCanvas hardwareCanvas) {
- DisplayList displayList = mDisplayList;
- if (displayList != null && displayList.isValid()) {
- // Note: This code assumes that the display list previously generated
- // is compatible with the given hardware canvas. That might not be true
- // if we start using multiple different types of hardware canvas
- // in the system someday.
- return displayList;
- }
-
- displayList = DisplayList.create(getClass().getName());
- mDisplayList = displayList;
-
- final Rect bounds = mBounds;
- final int width = bounds.width();
- final int height = bounds.height();
- final HardwareCanvas canvas = displayList.start(width, height);
- canvas.onPreDraw(null);
-
- // Draw the display list with origin (0,0) so that if the position
- // changes then we can translate without recreating the display list.
- final int restoreCount = canvas.save();
- try {
- canvas.translate(-bounds.left, -bounds.top);
- onDraw(canvas);
- } finally {
- canvas.restoreToCount(restoreCount);
- canvas.onPostDraw();
- displayList.end();
- }
-
- displayList.setLeftTopRightBottom(0, 0, width, height);
- displayList.setClipToBounds(false);
- return displayList;
- }
-
- private void invalidateDisplayList() {
- mDisplayList = null;
- }
+ public abstract void draw(Canvas canvas);
/**
* Specify a bounding rectangle for the Drawable. This is where the drawable
@@ -246,11 +163,10 @@
if (oldBounds.left != left || oldBounds.top != top ||
oldBounds.right != right || oldBounds.bottom != bottom) {
- if (oldBounds.right - oldBounds.left != right - left
- || oldBounds.bottom - oldBounds.top != bottom - top) {
- invalidateDisplayList();
+ if (!oldBounds.isEmpty()) {
+ // first invalidate the previous bounds
+ invalidateSelf();
}
-
mBounds.set(left, top, right, bottom);
onBoundsChange(mBounds);
}
@@ -438,8 +354,6 @@
* @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public void invalidateSelf() {
- invalidateDisplayList();
-
final Callback callback = getCallback();
if (callback != null) {
callback.invalidateDrawable(this);
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 6a9454c..e654db1 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -266,7 +266,7 @@
* @see #setStroke(int, int)
*/
public void setStroke(int width, int color, float dashWidth, float dashGap) {
- mGradientState.setStroke(width, color, dashWidth, dashGap);
+ mGradientState.setStroke(width, ColorStateList.valueOf(color), dashWidth, dashGap);
setStrokeInternal(width, color, dashWidth, dashGap);
}
@@ -288,15 +288,15 @@
*/
public void setStroke(
int width, ColorStateList colorStateList, float dashWidth, float dashGap) {
+ mGradientState.setStroke(width, colorStateList, dashWidth, dashGap);
+ final int color;
if (colorStateList == null) {
- setStroke(width, Color.TRANSPARENT, dashWidth, dashGap);
+ color = Color.TRANSPARENT;
} else {
- mGradientState.setStroke(width, colorStateList, dashWidth, dashGap);
-
final int[] stateSet = getState();
- final int color = colorStateList.getColorForState(stateSet, 0);
- setStrokeInternal(width, color, dashWidth, dashGap);
+ color = colorStateList.getColorForState(stateSet, 0);
}
+ setStrokeInternal(width, color, dashWidth, dashGap);
}
private void setStrokeInternal(int width, int color, float dashWidth, float dashGap) {
@@ -472,7 +472,7 @@
}
@Override
- protected void onDraw(Canvas canvas) {
+ public void draw(Canvas canvas) {
if (!ensureValidRect()) {
// nothing to draw
return;
@@ -529,8 +529,7 @@
mFillPaint.setAlpha(currFillAlpha);
mFillPaint.setDither(mDither);
mFillPaint.setColorFilter(mColorFilter);
- if (mColorFilter != null && !mGradientState.mHasSolidColor
- && mGradientState.mColorStateList == null) {
+ if (mColorFilter != null && mGradientState.mColorStateList == null) {
mFillPaint.setColor(mAlpha << 24);
}
if (haveStroke) {
@@ -672,7 +671,7 @@
* @see #setColors(int[])
*/
public void setColor(int argb) {
- mGradientState.setSolidColor(argb);
+ mGradientState.setColorStateList(ColorStateList.valueOf(argb));
mFillPaint.setColor(argb);
invalidateSelf();
}
@@ -691,14 +690,16 @@
* @see #mutate()
*/
public void setColor(ColorStateList colorStateList) {
+ mGradientState.setColorStateList(colorStateList);
+ final int color;
if (colorStateList == null) {
- setColor(Color.TRANSPARENT);
+ color = Color.TRANSPARENT;
} else {
- final int color = colorStateList.getColorForState(getState(), 0);
- mGradientState.setColorStateList(colorStateList);
- mFillPaint.setColor(color);
- invalidateSelf();
+ final int[] stateSet = getState();
+ color = colorStateList.getColorForState(stateSet, 0);
}
+ mFillPaint.setColor(color);
+ invalidateSelf();
}
@Override
@@ -910,7 +911,7 @@
// If we don't have a solid color, the alpha channel must be
// maxed out so that alpha modulation works correctly.
- if (!st.mHasSolidColor && st.mColorStateList == null) {
+ if (st.mColorStateList == null) {
mFillPaint.setColor(Color.BLACK);
}
}
@@ -1202,10 +1203,7 @@
public int[] mTempColors; // no need to copy
public float[] mTempPositions; // no need to copy
public float[] mPositions;
- public boolean mHasSolidColor;
- public int mSolidColor;
public int mStrokeWidth = -1; // if >= 0 use stroking.
- public int mStrokeColor;
public float mStrokeDashWidth;
public float mStrokeDashGap;
public float mRadius; // use this if mRadiusArray is null
@@ -1241,10 +1239,8 @@
if (state.mPositions != null) {
mPositions = state.mPositions.clone();
}
- mHasSolidColor = state.mHasSolidColor;
- mSolidColor = state.mSolidColor;
+ mStrokeColorStateList = state.mStrokeColorStateList;
mStrokeWidth = state.mStrokeWidth;
- mStrokeColor = state.mStrokeColor;
mStrokeDashWidth = state.mStrokeDashWidth;
mStrokeDashGap = state.mStrokeDashGap;
mRadius = state.mRadius;
@@ -1298,22 +1294,12 @@
}
public void setColors(int[] colors) {
- mHasSolidColor = false;
mColors = colors;
mColorStateList = null;
computeOpacity();
}
-
- public void setSolidColor(int argb) {
- mHasSolidColor = argb != Color.TRANSPARENT;
- mSolidColor = argb;
- mColors = null;
- mColorStateList = null;
- computeOpacity();
- }
public void setColorStateList(ColorStateList colorStateList) {
- mHasSolidColor = false;
mColors = null;
mColorStateList = colorStateList;
computeOpacity();
@@ -1336,9 +1322,6 @@
mOpaque = false;
return;
}
- } else if (!isOpaque(mStrokeColor)) {
- mOpaque = false;
- return;
}
}
@@ -1347,11 +1330,6 @@
return;
}
- if (mHasSolidColor) {
- mOpaque = isOpaque(mSolidColor);
- return;
- }
-
if (mColors != null) {
for (int i = 0; i < mColors.length; i++) {
if (!isOpaque(mColors[i])) {
@@ -1368,22 +1346,6 @@
return ((color >> 24) & 0xff) == 0xff;
}
- public void setStroke(int width, int color) {
- mStrokeWidth = width;
- mStrokeColor = color;
- mStrokeColorStateList = null;
- computeOpacity();
- }
-
- public void setStroke(int width, int color, float dashWidth, float dashGap) {
- mStrokeWidth = width;
- mStrokeColor = color;
- mStrokeColorStateList = null;
- mStrokeDashWidth = dashWidth;
- mStrokeDashGap = dashGap;
- computeOpacity();
- }
-
public void setStroke(
int width, ColorStateList colorStateList, float dashWidth, float dashGap) {
mStrokeWidth = width;
@@ -1426,9 +1388,7 @@
}
private void initializeWithState(GradientState state) {
- if (state.mHasSolidColor) {
- mFillPaint.setColor(state.mSolidColor);
- } else if (state.mColorStateList != null) {
+ if (state.mColorStateList != null) {
final int[] currentState = getState();
final int stateColor = state.mColorStateList.getColorForState(currentState, 0);
mFillPaint.setColor(stateColor);
@@ -1451,8 +1411,6 @@
final int strokeStateColor = state.mStrokeColorStateList.getColorForState(
currentState, 0);
mStrokePaint.setColor(strokeStateColor);
- } else {
- mStrokePaint.setColor(state.mStrokeColor);
}
if (state.mStrokeDashWidth != 0.0f) {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index ee64d7a..515d3c1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -223,7 +223,7 @@
}
@Override
- protected void onDraw(Canvas canvas) {
+ public void draw(Canvas canvas) {
final Rect bounds = getBounds();
final boolean needsMirroring = needsMirroring();
if (needsMirroring) {
diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java
index 2118b23..cb2d8f6 100644
--- a/graphics/java/android/graphics/drawable/PictureDrawable.java
+++ b/graphics/java/android/graphics/drawable/PictureDrawable.java
@@ -60,7 +60,7 @@
}
@Override
- protected void onDraw(Canvas canvas) {
+ public void draw(Canvas canvas) {
if (mPicture != null) {
Rect bounds = getBounds();
canvas.save();
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index aec3a4b..630dc2e 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -31,13 +31,14 @@
import java.io.IOException;
/**
- * <p>A Drawable that can rotate another Drawable based on the current level
- * value. The start and end angles of rotation can be controlled to map any
- * circular arc to the level values range.</p>
- *
- * <p>It can be defined in an XML file with the <code><rotate></code> element. For more
- * information, see the guide to <a
- * href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p>
+ * <p>
+ * A Drawable that can rotate another Drawable based on the current level value.
+ * The start and end angles of rotation can be controlled to map any circular
+ * arc to the level values range.
+ * <p>
+ * It can be defined in an XML file with the <code><rotate></code> element.
+ * For more information, see the guide to
+ * <a href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.
*
* @attr ref android.R.styleable#RotateDrawable_visible
* @attr ref android.R.styleable#RotateDrawable_fromDegrees
@@ -49,20 +50,21 @@
public class RotateDrawable extends Drawable implements Drawable.Callback {
private static final float MAX_LEVEL = 10000.0f;
- private RotateState mState;
+ private final RotateState mState;
+
private boolean mMutated;
/**
- * <p>Create a new rotating drawable with an empty state.</p>
+ * Create a new rotating drawable with an empty state.
*/
public RotateDrawable() {
this(null, null);
}
/**
- * <p>Create a new rotating drawable with the specified state. A copy of
+ * Create a new rotating drawable with the specified state. A copy of
* this state is used as the internal state for the newly created
- * drawable.</p>
+ * drawable.
*
* @param rotateState the state for this drawable
*/
@@ -70,28 +72,42 @@
mState = new RotateState(rotateState, this, res);
}
+ @Override
public void draw(Canvas canvas) {
- int saveCount = canvas.save();
-
- Rect bounds = mState.mDrawable.getBounds();
-
- int w = bounds.right - bounds.left;
- int h = bounds.bottom - bounds.top;
-
final RotateState st = mState;
-
- float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
- float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
+ final Drawable d = st.mDrawable;
+ final Rect bounds = d.getBounds();
+ final int w = bounds.right - bounds.left;
+ final int h = bounds.bottom - bounds.top;
+ final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+ final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
+ final int saveCount = canvas.save();
canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
-
- st.mDrawable.draw(canvas);
-
+ d.draw(canvas);
canvas.restoreToCount(saveCount);
}
/**
- * Returns the drawable rotated by this RotateDrawable.
+ * Sets the drawable rotated by this RotateDrawable.
+ *
+ * @param drawable The drawable to rotate
+ */
+ public void setDrawable(Drawable drawable) {
+ final Drawable oldDrawable = mState.mDrawable;
+ if (oldDrawable != drawable) {
+ if (oldDrawable != null) {
+ oldDrawable.setCallback(null);
+ }
+ mState.mDrawable = drawable;
+ if (drawable != null) {
+ drawable.setCallback(this);
+ }
+ }
+ }
+
+ /**
+ * @return The drawable rotated by this RotateDrawable
*/
public Drawable getDrawable() {
return mState.mDrawable;
@@ -103,7 +119,8 @@
| mState.mChangingConfigurations
| mState.mDrawable.getChangingConfigurations();
}
-
+
+ @Override
public void setAlpha(int alpha) {
mState.mDrawable.setAlpha(alpha);
}
@@ -113,14 +130,149 @@
return mState.mDrawable.getAlpha();
}
+ @Override
public void setColorFilter(ColorFilter cf) {
mState.mDrawable.setColorFilter(cf);
}
+ @Override
public int getOpacity() {
return mState.mDrawable.getOpacity();
}
+ /**
+ * Sets the start angle for rotation.
+ *
+ * @param fromDegrees Starting angle in degrees
+ */
+ public void setFromDegrees(float fromDegrees) {
+ if (mState.mFromDegrees != fromDegrees) {
+ mState.mFromDegrees = fromDegrees;
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * @return The starting angle for rotation in degrees
+ */
+ public float getFromDegrees() {
+ return mState.mFromDegrees;
+ }
+
+ /**
+ * Sets the end angle for rotation.
+ *
+ * @param toDegrees Ending angle in degrees
+ */
+ public void setToDegrees(float toDegrees) {
+ if (mState.mToDegrees != toDegrees) {
+ mState.mToDegrees = toDegrees;
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * @return The ending angle for rotation in degrees
+ */
+ public float getToDegrees() {
+ return mState.mToDegrees;
+ }
+
+ /**
+ * Sets the X position around which the drawable is rotated.
+ *
+ * @param pivotX X position around which to rotate. If the X pivot is
+ * relative, the position represents a fraction of the drawable
+ * width. Otherwise, the position represents an absolute value in
+ * pixels.
+ * @see #setPivotXRelative(boolean)
+ */
+ public void setPivotX(float pivotX) {
+ if (mState.mPivotX == pivotX) {
+ mState.mPivotX = pivotX;
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * @return X position around which to rotate
+ * @see #setPivotX(float)
+ */
+ public float getPivotX() {
+ return mState.mPivotX;
+ }
+
+ /**
+ * Sets whether the X pivot value represents a fraction of the drawable
+ * width or an absolute value in pixels.
+ *
+ * @param relative True if the X pivot represents a fraction of the drawable
+ * width, or false if it represents an absolute value in pixels
+ */
+ public void setPivotXRelative(boolean relative) {
+ if (mState.mPivotXRel == relative) {
+ mState.mPivotXRel = relative;
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * @return True if the X pivot represents a fraction of the drawable width,
+ * or false if it represents an absolute value in pixels
+ * @see #setPivotXRelative(boolean)
+ */
+ public boolean isPivotXRelative() {
+ return mState.mPivotXRel;
+ }
+
+ /**
+ * Sets the Y position around which the drawable is rotated.
+ *
+ * @param pivotY Y position around which to rotate. If the Y pivot is
+ * relative, the position represents a fraction of the drawable
+ * height. Otherwise, the position represents an absolute value
+ * in pixels.
+ * @see #setPivotYRelative(boolean)
+ */
+ public void setPivotY(float pivotY) {
+ if (mState.mPivotY == pivotY) {
+ mState.mPivotY = pivotY;
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * @return Y position around which to rotate
+ * @see #setPivotY(float)
+ */
+ public float getPivotY() {
+ return mState.mPivotY;
+ }
+
+ /**
+ * Sets whether the Y pivot value represents a fraction of the drawable
+ * height or an absolute value in pixels.
+ *
+ * @param relative True if the Y pivot represents a fraction of the drawable
+ * height, or false if it represents an absolute value in pixels
+ */
+ public void setPivotYRelative(boolean relative) {
+ if (mState.mPivotYRel == relative) {
+ mState.mPivotYRel = relative;
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * @return True if the Y pivot represents a fraction of the drawable height,
+ * or false if it represents an absolute value in pixels
+ * @see #setPivotYRelative(boolean)
+ */
+ public boolean isPivotYRelative() {
+ return mState.mPivotYRel;
+ }
+
+ @Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
if (callback != null) {
@@ -128,6 +280,7 @@
}
}
+ @Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
final Callback callback = getCallback();
if (callback != null) {
@@ -135,6 +288,7 @@
}
}
+ @Override
public void unscheduleDrawable(Drawable who, Runnable what) {
final Callback callback = getCallback();
if (callback != null) {
@@ -157,10 +311,10 @@
public boolean isStateful() {
return mState.mDrawable.isStateful();
}
-
+
@Override
protected boolean onStateChange(int[] state) {
- boolean changed = mState.mDrawable.setState(state);
+ final boolean changed = mState.mDrawable.setState(state);
onBoundsChange(getBounds());
return changed;
}
@@ -172,7 +326,7 @@
mState.mCurrentDegrees = mState.mFromDegrees +
(mState.mToDegrees - mState.mFromDegrees) *
- ((float) level / MAX_LEVEL);
+ (level / MAX_LEVEL);
invalidateSelf();
return true;
@@ -206,16 +360,15 @@
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
throws XmlPullParserException, IOException {
-
- TypedArray a = r.obtainAttributes(attrs,
+ final TypedArray a = r.obtainAttributes(attrs,
com.android.internal.R.styleable.RotateDrawable);
super.inflateWithAttributes(r, parser, a,
com.android.internal.R.styleable.RotateDrawable_visible);
-
+
TypedValue tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotX);
- boolean pivotXRel;
- float pivotX;
+ final boolean pivotXRel;
+ final float pivotX;
if (tv == null) {
pivotXRel = true;
pivotX = 0.5f;
@@ -223,10 +376,10 @@
pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
}
-
+
tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotY);
- boolean pivotYRel;
- float pivotY;
+ final boolean pivotYRel;
+ final float pivotY;
if (tv == null) {
pivotYRel = true;
pivotY = 0.5f;
@@ -235,12 +388,12 @@
pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
}
- float fromDegrees = a.getFloat(
+ final float fromDegrees = a.getFloat(
com.android.internal.R.styleable.RotateDrawable_fromDegrees, 0.0f);
- float toDegrees = a.getFloat(
+ final float toDegrees = a.getFloat(
com.android.internal.R.styleable.RotateDrawable_toDegrees, 360.0f);
- int res = a.getResourceId(
+ final int res = a.getResourceId(
com.android.internal.R.styleable.RotateDrawable_drawable, 0);
Drawable drawable = null;
if (res > 0) {
@@ -248,8 +401,8 @@
}
a.recycle();
-
- int outerDepth = parser.getDepth();
+
+ final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
(type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -268,13 +421,15 @@
Log.w("drawable", "No drawable specified for <rotate>");
}
- mState.mDrawable = drawable;
- mState.mPivotXRel = pivotXRel;
- mState.mPivotX = pivotX;
- mState.mPivotYRel = pivotYRel;
- mState.mPivotY = pivotY;
- mState.mFromDegrees = mState.mCurrentDegrees = fromDegrees;
- mState.mToDegrees = toDegrees;
+ final RotateState st = mState;
+ st.mDrawable = drawable;
+ st.mPivotXRel = pivotXRel;
+ st.mPivotX = pivotX;
+ st.mPivotYRel = pivotYRel;
+ st.mPivotY = pivotY;
+ st.mFromDegrees = fromDegrees;
+ st.mCurrentDegrees = fromDegrees;
+ st.mToDegrees = toDegrees;
if (drawable != null) {
drawable.setCallback(this);
@@ -291,15 +446,15 @@
}
/**
- * <p>Represents the state of a rotation for a given drawable. The same
+ * Represents the state of a rotation for a given drawable. The same
* rotate drawable can be invoked with different states to drive several
- * rotations at the same time.</p>
+ * rotations at the same time.
*/
final static class RotateState extends Drawable.ConstantState {
Drawable mDrawable;
int mChangingConfigurations;
-
+
boolean mPivotXRel;
float mPivotX;
boolean mPivotYRel;
@@ -311,7 +466,7 @@
float mCurrentDegrees;
private boolean mCanConstantState;
- private boolean mCheckedConstantState;
+ private boolean mCheckedConstantState;
public RotateState(RotateState source, RotateDrawable owner, Resources res) {
if (source != null) {
@@ -336,12 +491,12 @@
public Drawable newDrawable() {
return new RotateDrawable(this, null);
}
-
+
@Override
public Drawable newDrawable(Resources res) {
return new RotateDrawable(this, res);
}
-
+
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 9ca3bbf..93f2dc6 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -210,7 +210,7 @@
}
@Override
- protected void onDraw(Canvas canvas) {
+ public void draw(Canvas canvas) {
Rect r = getBounds();
Paint paint = mShapeState.mPaint;
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 09e2058..4c2299e 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -653,11 +653,9 @@
Vector2 penumbra[k];
int penumbraLength = hull(shadowRegion, shadowRegionLength, penumbra);
- // no real umbra make a fake one
+ Vector2 fakeUmbra[polyLength];
if (umbraLength < 3) {
- // The shadow from the centroid of the light polygon.
- Vector2 centShadow[polyLength];
-
+ // If there is no real umbra, make a fake one.
for (int i = 0; i < polyLength; i++) {
float t = lightCenter.z - poly[i].z;
if (t == 0) {
@@ -667,23 +665,23 @@
float x = lightCenter.x - t * (lightCenter.x - poly[i].x);
float y = lightCenter.y - t * (lightCenter.y - poly[i].y);
- centShadow[i].x = x;
- centShadow[i].y = y;
+ fakeUmbra[i].x = x;
+ fakeUmbra[i].y = y;
}
// Shrink the centroid's shadow by 10%.
// TODO: Study the magic number of 10%.
- Vector2 shadowCentroid = centroid2d(centShadow, polyLength);
+ Vector2 shadowCentroid = centroid2d(fakeUmbra, polyLength);
for (int i = 0; i < polyLength; i++) {
- centShadow[i] = shadowCentroid * (1.0f - SHADOW_SHRINK_SCALE) +
- centShadow[i] * SHADOW_SHRINK_SCALE;
+ fakeUmbra[i] = shadowCentroid * (1.0f - SHADOW_SHRINK_SCALE) +
+ fakeUmbra[i] * SHADOW_SHRINK_SCALE;
}
#if DEBUG_SHADOW
ALOGD("No real umbra make a fake one, centroid2d = %f , %f",
shadowCentroid.x, shadowCentroid.y);
#endif
// Set the fake umbra, whose size is the same as the original polygon.
- umbra = centShadow;
+ umbra = fakeUmbra;
umbraLength = polyLength;
}
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 7c0735b..f82ca22 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -591,7 +591,7 @@
icon.setImageDrawable(mIcon);
icon.setScaleType(ScaleType.CENTER_CROP);
} else if (mIconResId != 0) {
- icon.setImageDrawable(context.getResources().getDrawable(mIconResId));
+ icon.setImageDrawable(context.getDrawable(mIconResId));
}
if (mMessage != null) {
messageView.setText(mMessage);
@@ -681,7 +681,7 @@
boolean on = ((mState == State.On) || (mState == State.TurningOn));
if (icon != null) {
- icon.setImageDrawable(context.getResources().getDrawable(
+ icon.setImageDrawable(context.getDrawable(
(on ? mEnabledIconResId : mDisabledIconResid)));
icon.setEnabled(enabled);
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index d0abe9c..c73d90a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -22,6 +22,8 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.*;
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
import android.app.ActivityOptions;
import android.transition.Scene;
import android.transition.Transition;
@@ -88,6 +90,7 @@
import android.view.ViewParent;
import android.view.ViewRootImpl;
import android.view.ViewStub;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -114,6 +117,8 @@
private final static String TAG = "PhoneWindow";
private final static boolean SWEEP_OPEN_MENU = false;
+ private static final long MAX_TRANSITION_START_WAIT = 500;
+ private static final long MAX_TRANSITION_FINISH_WAIT = 1000;
/**
* Simple callback used by the context menu and its submenus. The options
@@ -136,22 +141,21 @@
private ViewGroup mContentParent;
SurfaceHolder.Callback2 mTakeSurfaceCallback;
-
+
InputQueue.Callback mTakeInputQueueCallback;
-
+
private boolean mIsFloating;
private LayoutInflater mLayoutInflater;
private TextView mTitleView;
-
+
private ActionBarView mActionBar;
private ActionMenuPresenterCallback mActionMenuPresenterCallback;
private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
private TransitionManager mTransitionManager;
private Scene mContentScene;
- private Bundle mTransitionOptions;
// The icon resource has been explicitly set elsewhere
// and should not be overwritten with a default.
@@ -233,6 +237,10 @@
}
};
+ private ActivityOptions mActivityOptions;
+ private SceneTransitionListener mSceneTransitionListener;
+ private boolean mFadeEarly = true;
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
@@ -303,11 +311,6 @@
}
@Override
- public void setTransitionOptions(Bundle options) {
- mTransitionOptions = options;
- }
-
- @Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
@@ -378,26 +381,11 @@
}
private void transitionTo(Scene scene) {
- Transition selected = null;
- if (mTransitionOptions != null) {
- final ActivityOptions opts = new ActivityOptions(mTransitionOptions);
- mTransitionOptions = null;
-
- String selectedName = null;
- for (String sceneName : opts.getDestSceneNames()) {
- final Transition t = mTransitionManager.getNamedTransition(sceneName, scene);
- if (t != null) {
- // TODO handle args/state; inject into t/clone with params
- selected = t;
- selectedName = sceneName;
- break;
- }
+ if (mContentScene == null) {
+ scene.enter();
+ if (mActivityOptions != null) {
+ new EnterScene().start();
}
- opts.dispatchSceneTransitionStarted(selectedName);
- }
-
- if (selected != null) {
- TransitionManager.go(scene, selected);
} else {
mTransitionManager.transitionTo(scene);
}
@@ -413,11 +401,11 @@
public void takeSurface(SurfaceHolder.Callback2 callback) {
mTakeSurfaceCallback = callback;
}
-
+
public void takeInputQueue(InputQueue.Callback callback) {
mTakeInputQueueCallback = callback;
}
-
+
@Override
public boolean isFloating() {
return mIsFloating;
@@ -704,7 +692,7 @@
// Otherwise, set the normal panel background
backgroundResId = st.background;
}
- st.decorView.setWindowBackground(getContext().getResources().getDrawable(
+ st.decorView.setWindowBackground(getContext().getDrawable(
backgroundResId));
ViewParent shownPanelParent = st.shownPanelView.getParent();
@@ -1289,7 +1277,7 @@
if (st.resid != resId) {
st.resid = resId;
st.uri = null;
- st.local = getContext().getResources().getDrawable(resId);
+ st.local = getContext().getDrawable(resId);
updateDrawable(featureId, st, false);
}
} else {
@@ -2305,7 +2293,7 @@
if (mMenuBackground == null && mFeatureId < 0
&& getAttributes().height
== WindowManager.LayoutParams.MATCH_PARENT) {
- mMenuBackground = getContext().getResources().getDrawable(
+ mMenuBackground = getContext().getDrawable(
com.android.internal.R.drawable.menu_background);
}
if (mMenuBackground != null) {
@@ -3122,12 +3110,12 @@
if (getContainer() == null) {
Drawable drawable = mBackgroundDrawable;
if (mBackgroundResource != 0) {
- drawable = getContext().getResources().getDrawable(mBackgroundResource);
+ drawable = getContext().getDrawable(mBackgroundResource);
}
mDecor.setWindowBackground(drawable);
drawable = null;
if (mFrameResource != 0) {
- drawable = getContext().getResources().getDrawable(mFrameResource);
+ drawable = getContext().getDrawable(mFrameResource);
}
mDecor.setWindowFrame(drawable);
@@ -3553,6 +3541,12 @@
return mVolumeControlStreamType;
}
+ private boolean isTranslucent() {
+ TypedArray a = getWindowStyle();
+ return a.getBoolean(a.getResourceId(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, 0), false);
+ }
+
private static final class DrawableFeatureState {
DrawableFeatureState(int _featureId) {
featureId = _featureId;
@@ -3986,4 +3980,218 @@
void sendCloseSystemWindows(String reason) {
PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
}
+
+ @Override
+ public void setTransitionOptions(ActivityOptions options, SceneTransitionListener listener) {
+ mSceneTransitionListener = listener;
+ mActivityOptions = options;
+ }
+
+ @Override
+ public void setEarlyBackgroundTransition(boolean fadeEarly) {
+ mFadeEarly = fadeEarly;
+ }
+
+ @Override
+ public void startExitTransition(ActivityOptions activityOptions) {
+ Transition transition = mTransitionManager.getNamedTransition(getContentScene(), "null");
+ if (transition == null) {
+ transition = TransitionManager.getDefaultTransition().clone();
+ }
+ activityOptions.setExitTransition(transition, new ActivityOptions.SharedElementSource() {
+ @Override
+ public int getTextureId() {
+ // TODO: move shared elements to a layer and return the texture id
+ recurseHideExitingSharedElements(mContentParent);
+ return 0;
+ }
+ });
+ ViewGroup sceneRoot = getContentScene().getSceneRoot();
+ TransitionManager.beginDelayedTransition(sceneRoot, transition);
+ recurseExitNonSharedElements(mContentParent);
+ }
+
+ private static void recurseExitNonSharedElements(ViewGroup viewGroup) {
+ int numChildren = viewGroup.getChildCount();
+ for (int i = 0; i < numChildren; i++) {
+ View child = viewGroup.getChildAt(i);
+ if (child.getSharedElementName() != null || (child.getVisibility() != View.VISIBLE)) {
+ continue;
+ }
+ if (child instanceof ViewGroup && !((ViewGroup)child).isTransitionGroup()) {
+ recurseExitNonSharedElements((ViewGroup) child);
+ } else {
+ child.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ private static void recurseHideViews(ViewGroup viewGroup, ArrayList<View> nonSharedElements,
+ ArrayList<View> sharedElements) {
+ int numChildren = viewGroup.getChildCount();
+ for (int i = 0; i < numChildren; i++) {
+ View child = viewGroup.getChildAt(i);
+ if (child.getVisibility() != View.VISIBLE) {
+ continue;
+ }
+ if (child.getSharedElementName() != null) {
+ sharedElements.add(child);
+ child.setVisibility(View.INVISIBLE);
+ } else if (child instanceof ViewGroup && !((ViewGroup)child).isTransitionGroup()) {
+ recurseHideViews((ViewGroup) child, nonSharedElements, sharedElements);
+ } else {
+ nonSharedElements.add(child);
+ child.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ private static void recurseHideExitingSharedElements(ViewGroup viewGroup) {
+ int numChildren = viewGroup.getChildCount();
+ for (int i = 0; i < numChildren; i++) {
+ View child = viewGroup.getChildAt(i);
+ if (child.getVisibility() != View.VISIBLE) {
+ continue;
+ }
+ if (child.getSharedElementName() != null) {
+ child.setVisibility(View.INVISIBLE);
+ } else if (child instanceof ViewGroup) {
+ ViewGroup childViewGroup = (ViewGroup) child;
+ recurseHideExitingSharedElements(childViewGroup);
+ }
+ }
+ }
+
+ /**
+ * Provides code for handling the Activity transition entering scene.
+ * When the first scene is laid out (onPreDraw), it makes views invisible.
+ * It then starts the entering transition by making non-shared elements visible. When
+ * the entering transition is started, the calling Activity is notified that
+ * this Activity is ready to receive the shared element. When the calling Activity notifies
+ * that the shared element is ready, this Activity is notified through the
+ * SceneTransitionListener.
+ *
+ * This class also takes into account fading the background -- either waiting until the
+ * shared element is ready or the calling Activity's exit transition is complete.
+ */
+ private class EnterScene implements ViewTreeObserver.OnPreDrawListener, Runnable,
+ ActivityOptions.ActivityTransitionTarget, Animator.AnimatorListener {
+ private boolean mSharedElementReadyReceived;
+ private boolean mAllDone;
+ private Handler mHandler = new Handler();
+ private boolean mEnterTransitionStarted;
+ private ArrayList<View> mSharedElements = new ArrayList<View>();
+
+ public EnterScene() {
+ mSceneTransitionListener.nullPendingTransition();
+ Drawable background = getDecorView().getBackground();
+ if (background != null) {
+ setBackgroundDrawable(null);
+ background.setAlpha(0);
+ setBackgroundDrawable(background);
+ }
+ mSceneTransitionListener.convertToTranslucent();
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ ViewTreeObserver observer = mContentParent.getViewTreeObserver();
+ observer.removeOnPreDrawListener(this);
+ if (!mEnterTransitionStarted && mSceneTransitionListener != null) {
+ mEnterTransitionStarted = true;
+ ArrayList<View> enteringViews = new ArrayList<View>();
+ recurseHideViews(mContentParent, enteringViews, mSharedElements);
+ Transition transition = getTransitionManager().getNamedTransition("null",
+ mContentScene);
+ if (transition == null) {
+ transition = TransitionManager.getDefaultTransition().clone();
+ }
+ TransitionManager.beginDelayedTransition(mContentParent, transition);
+ for (View hidden : enteringViews) {
+ hidden.setVisibility(View.VISIBLE);
+ }
+ observer.addOnPreDrawListener(this);
+ } else {
+ mHandler.postDelayed(this, MAX_TRANSITION_START_WAIT);
+ mActivityOptions.dispatchSceneTransitionStarted(this);
+ }
+ return true;
+ }
+
+ public void start() {
+ ViewTreeObserver observer = mContentParent.getViewTreeObserver();
+ observer.addOnPreDrawListener(this);
+ }
+
+ @Override
+ public void run() {
+ exitTransitionComplete();
+ }
+
+ @Override
+ public void sharedElementTransitionComplete() {
+ if (!mSharedElementReadyReceived) {
+ mSharedElementReadyReceived = true;
+ mHandler.removeCallbacks(this);
+ mHandler.postDelayed(this, MAX_TRANSITION_FINISH_WAIT);
+ for (View sharedElement: mSharedElements) {
+ sharedElement.setVisibility(View.VISIBLE);
+ }
+ mSharedElements.clear();
+ mContentParent.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mContentParent.getViewTreeObserver().removeOnPreDrawListener(this);
+ mSceneTransitionListener.enterSharedElement(
+ mActivityOptions.getSceneTransitionArgs());
+ return false;
+ }
+ });
+ if (mFadeEarly) {
+ fadeInBackground();
+ }
+ }
+ }
+
+ private void fadeInBackground() {
+ Drawable background = getDecorView().getBackground();
+ if (background == null) {
+ mSceneTransitionListener.convertFromTranslucent();
+ } else {
+ ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
+ animator.addListener(this);
+ animator.start();
+ }
+ }
+
+ @Override
+ public void exitTransitionComplete() {
+ if (mAllDone) {
+ return;
+ }
+ mAllDone = true;
+ sharedElementTransitionComplete();
+ mHandler.removeCallbacks(this);
+ if (!mFadeEarly) {
+ fadeInBackground();
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSceneTransitionListener.convertFromTranslucent();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8e83255..ce6166a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -5040,7 +5040,6 @@
@Override
public void keepScreenOnStoppedLw() {
if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotHidden()) {
- long curTime = SystemClock.uptimeMillis();
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
}
diff --git a/preloaded-classes b/preloaded-classes
index 42412c6..4d79e4b 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -2455,8 +2455,6 @@
org.apache.harmony.security.fortress.Engine$SpiAndProvider
org.apache.harmony.security.fortress.SecurityAccess
org.apache.harmony.security.fortress.Services
-org.apache.harmony.security.provider.cert.DRLCertFactory
-org.apache.harmony.security.provider.cert.X509CertImpl
org.apache.harmony.security.provider.crypto.CryptoProvider
org.apache.harmony.security.utils.AlgNameMapper
org.apache.harmony.security.utils.ObjectIdentifier
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 015185f..9349730 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -169,9 +169,9 @@
private static final String TAG = "ConnectivityService";
private static final boolean DBG = true;
- private static final boolean VDBG = false;
+ private static final boolean VDBG = true;
- private static final boolean LOGD_RULES = false;
+ private static final boolean LOGD_RULES = true;
// TODO: create better separation between radio types and network types
@@ -4495,11 +4495,16 @@
* @param seconds
*/
private static void sleep(int seconds) {
- try {
- Thread.sleep(seconds * 1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
+ log("XXXXX sleeping for " + seconds + " sec");
+ long stopTime = System.nanoTime() + (seconds * 1000000000);
+ long sleepTime;
+ while ((sleepTime = stopTime - System.nanoTime()) > 0) {
+ try {
+ Thread.sleep(sleepTime / 1000000);
+ } catch (InterruptedException ignored) {
+ }
}
+ log("XXXXX returning from sleep");
}
private static void log(String s) {
diff --git a/services/core/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java
index b0a1aca..acc6abe 100644
--- a/services/core/java/com/android/server/IdleMaintenanceService.java
+++ b/services/core/java/com/android/server/IdleMaintenanceService.java
@@ -16,22 +16,38 @@
package com.android.server;
-import android.app.Activity;
-import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.maintenance.IIdleCallback;
+import android.app.maintenance.IIdleService;
+import android.app.maintenance.IdleService;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.WorkSource;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
/**
* This service observes the device state and when applicable sends
@@ -47,12 +63,15 @@
*
* The end of a maintenance window is announced only if: a start was
* announced AND the screen turned on or a dream was stopped.
+ *
+ * Method naming note:
+ * Methods whose name ends with "Tm" must only be called from the main thread.
*/
public class IdleMaintenanceService extends BroadcastReceiver {
private static final boolean DEBUG = false;
- private static final String LOG_TAG = IdleMaintenanceService.class.getSimpleName();
+ private static final String TAG = IdleMaintenanceService.class.getSimpleName();
private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1;
@@ -74,36 +93,480 @@
private static final String ACTION_FORCE_IDLE_MAINTENANCE =
"com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE";
- private static final Intent sIdleMaintenanceStartIntent;
- static {
- sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
- sIdleMaintenanceStartIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- };
+ static final int MSG_OP_COMPLETE = 1;
+ static final int MSG_IDLE_FINISHED = 2;
+ static final int MSG_TIMEOUT = 3;
- private static final Intent sIdleMaintenanceEndIntent;
- static {
- sIdleMaintenanceEndIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_END);
- sIdleMaintenanceEndIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- }
+ // when a timeout happened, what were we expecting?
+ static final int VERB_BINDING = 1;
+ static final int VERB_IDLING = 2;
+ static final int VERB_ENDING = 3;
+
+ // What are our relevant timeouts / allocated slices?
+ static final long OP_TIMEOUT = 8 * 1000; // 8 seconds to bind or ack the start
+ static final long IDLE_TIMESLICE = 10 * 60 * 1000; // ten minutes for each idler
private final AlarmManager mAlarmService;
-
private final BatteryService mBatteryService;
-
private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent;
-
private final Context mContext;
-
private final WakeLock mWakeLock;
-
- private final Handler mHandler;
+ private final WorkSource mSystemWorkSource = new WorkSource(Process.myUid());
private long mLastIdleMaintenanceStartTimeMillis;
-
private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
-
private boolean mIdleMaintenanceStarted;
+ final IdleCallback mCallback;
+ final Handler mHandler;
+
+ final Random mTokenGenerator = new Random();
+
+ int makeToken() {
+ int token;
+ do {
+ token = mTokenGenerator.nextInt(Integer.MAX_VALUE);
+ } while (token == 0);
+ return token;
+ }
+
+ class ActiveTask {
+ public IdleServiceInfo who;
+ public int verb;
+ public int token;
+
+ ActiveTask(IdleServiceInfo target, int action) {
+ who = target;
+ verb = action;
+ token = makeToken();
+ }
+
+ @Override
+ public String toString() {
+ return "ActiveTask{" + Integer.toHexString(this.hashCode())
+ + " : verb=" + verb
+ + " : token=" + token
+ + " : "+ who + "}";
+ }
+ }
+
+ // What operations are in flight?
+ final SparseArray<ActiveTask> mPendingOperations = new SparseArray<ActiveTask>();
+
+ // Idle service queue management
+ class IdleServiceInfo {
+ public final ComponentName componentName;
+ public final int uid;
+ public IIdleService service;
+
+ IdleServiceInfo(ResolveInfo info, ComponentName cname) {
+ componentName = cname; // derived from 'info' but this avoids an extra object
+ uid = info.serviceInfo.applicationInfo.uid;
+ service = null;
+ }
+
+ @Override
+ public int hashCode() {
+ return componentName.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "IdleServiceInfo{" + componentName
+ + " / " + (service == null ? "null" : service.asBinder()) + "}";
+ }
+ }
+
+ final ArrayMap<ComponentName, IdleServiceInfo> mIdleServices =
+ new ArrayMap<ComponentName, IdleServiceInfo>();
+ final LinkedList<IdleServiceInfo> mIdleServiceQueue = new LinkedList<IdleServiceInfo>();
+ IdleServiceInfo mCurrentIdler; // set when we've committed to launching an idler
+ IdleServiceInfo mLastIdler; // end of queue when idling begins
+
+ void reportNoTimeout(int token, boolean result) {
+ final Message msg = mHandler.obtainMessage(MSG_OP_COMPLETE, result ? 1 : 0, token);
+ mHandler.sendMessage(msg);
+ }
+
+ // Binder acknowledgment trampoline
+ class IdleCallback extends IIdleCallback.Stub {
+ @Override
+ public void acknowledgeStart(int token, boolean result) throws RemoteException {
+ reportNoTimeout(token, result);
+ }
+
+ @Override
+ public void acknowledgeStop(int token) throws RemoteException {
+ reportNoTimeout(token, false);
+ }
+
+ @Override
+ public void idleFinished(int token) throws RemoteException {
+ if (DEBUG) {
+ Slog.v(TAG, "idleFinished: " + token);
+ }
+ final Message msg = mHandler.obtainMessage(MSG_IDLE_FINISHED, 0, token);
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ // Stuff that we run on a Handler
+ class IdleHandler extends Handler {
+ public IdleHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ final int token = msg.arg2;
+
+ switch (msg.what) {
+ case MSG_OP_COMPLETE: {
+ if (DEBUG) {
+ Slog.i(TAG, "MSG_OP_COMPLETE of " + token);
+ }
+ ActiveTask task = mPendingOperations.get(token);
+ if (task != null) {
+ mPendingOperations.remove(token);
+ removeMessages(MSG_TIMEOUT);
+
+ handleOpCompleteTm(task, msg.arg1);
+ } else {
+ // Can happen in a race between timeout and actual
+ // (belated) completion of a "begin idling" or similar
+ // operation. In that state we've already processed the
+ // timeout, so we intentionally no-op here.
+ if (DEBUG) {
+ Slog.w(TAG, "Belated op-complete of " + token);
+ }
+ }
+ break;
+ }
+
+ case MSG_IDLE_FINISHED: {
+ if (DEBUG) {
+ Slog.i(TAG, "MSG_IDLE_FINISHED of " + token);
+ }
+ ActiveTask task = mPendingOperations.get(token);
+ if (task != null) {
+ if (DEBUG) {
+ Slog.i(TAG, "... removing task " + token);
+ }
+ mPendingOperations.remove(token);
+ removeMessages(MSG_TIMEOUT);
+
+ handleIdleFinishedTm(task);
+ } else {
+ // Can happen "legitimately" from an app explicitly calling
+ // idleFinished() after already having been told that its slice
+ // has ended.
+ if (DEBUG) {
+ Slog.w(TAG, "Belated idle-finished of " + token);
+ }
+ }
+ break;
+ }
+
+ case MSG_TIMEOUT: {
+ if (DEBUG) {
+ Slog.i(TAG, "MSG_TIMEOUT of " + token);
+ }
+ ActiveTask task = mPendingOperations.get(token);
+ if (task != null) {
+ mPendingOperations.remove(token);
+ removeMessages(MSG_OP_COMPLETE);
+
+ handleTimeoutTm(task);
+ } else {
+ // This one should not happen; we flushed timeout messages
+ // whenever we entered a state after which we have established
+ // that they are not appropriate.
+ Slog.w(TAG, "Unexpected timeout of " + token);
+ }
+ break;
+ }
+
+ default:
+ Slog.w(TAG, "Unknown message: " + msg.what);
+ }
+ }
+ }
+
+ void handleTimeoutTm(ActiveTask task) {
+ switch (task.verb) {
+ case VERB_BINDING: {
+ // We were trying to bind to this service, but it wedged or otherwise
+ // failed to respond in time. Let it stay in the queue for the next
+ // time around, but just give up on it for now and go on to the next.
+ startNextIdleServiceTm();
+ break;
+ }
+ case VERB_IDLING: {
+ // The service has reached the end of its designated idle timeslice.
+ // This is not considered an error.
+ if (DEBUG) {
+ Slog.i(TAG, "Idler reached end of timeslice: " + task.who);
+ }
+ sendEndIdleTm(task.who);
+ break;
+ }
+ case VERB_ENDING: {
+ if (mCurrentIdler == task.who) {
+ if (DEBUG) {
+ Slog.i(TAG, "Task timed out when ending; unbind needed");
+ }
+ handleIdleFinishedTm(task);
+ } else {
+ if (DEBUG) {
+ Slog.w(TAG, "Ending timeout for non-current idle service!");
+ }
+ }
+ break;
+ }
+ default: {
+ Slog.w(TAG, "Unknown timeout state " + task.verb);
+ break;
+ }
+ }
+ }
+
+ void handleOpCompleteTm(ActiveTask task, int result) {
+ if (DEBUG) {
+ Slog.i(TAG, "handleOpComplete : task=" + task + " result=" + result);
+ }
+ if (task.verb == VERB_IDLING) {
+ // If the service was told to begin idling and responded positively, then
+ // it has begun idling and will eventually either explicitly finish, or
+ // reach the end of its allotted timeslice. It's running free now, so we
+ // just schedule the idle-expiration timeout under the token it's already been
+ // given and let it keep going.
+ if (result != 0) {
+ scheduleOpTimeoutTm(task);
+ } else {
+ // The idle service has indicated that it does not, in fact,
+ // need to run at present, so we immediately indicate that it's
+ // to finish idling, and go on to the next idler.
+ if (DEBUG) {
+ Slog.i(TAG, "Idler declined idling; moving along");
+ }
+ sendEndIdleTm(task.who);
+ }
+ } else {
+ // In the idling case, the task will be cleared either as the result of a timeout
+ // or of an explicit idleFinished(). For all other operations (binding, ending) we
+ // are done with the task as such, so we remove it from our bookkeeping.
+ if (DEBUG) {
+ Slog.i(TAG, "Clearing task " + task);
+ }
+ mPendingOperations.remove(task.token);
+ if (task.verb == VERB_ENDING) {
+ // The last bit of handshaking around idle cessation for this target
+ handleIdleFinishedTm(task);
+ }
+ }
+ }
+
+ void handleIdleFinishedTm(ActiveTask task) {
+ final IdleServiceInfo who = task.who;
+ if (who == mCurrentIdler) {
+ if (DEBUG) {
+ Slog.i(TAG, "Current idler has finished: " + who);
+ Slog.i(TAG, "Attributing wakelock to system work source");
+ }
+ mContext.unbindService(mConnection);
+ startNextIdleServiceTm();
+ } else {
+ Slog.w(TAG, "finish from non-current idle service? " + who);
+ }
+ }
+
+ void updateIdleServiceQueueTm() {
+ if (DEBUG) {
+ Slog.i(TAG, "Updating idle service queue");
+ }
+ PackageManager pm = mContext.getPackageManager();
+ Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
+ List<ResolveInfo> services = pm.queryIntentServices(idleIntent, 0);
+ for (ResolveInfo info : services) {
+ if (info.serviceInfo != null) {
+ if (IdleService.PERMISSION_BIND.equals(info.serviceInfo.permission)) {
+ final ComponentName componentName = new ComponentName(
+ info.serviceInfo.packageName,
+ info.serviceInfo.name);
+ if (DEBUG) {
+ Slog.i(TAG, " - " + componentName);
+ }
+ if (!mIdleServices.containsKey(componentName)) {
+ if (DEBUG) {
+ Slog.i(TAG, " + not known; adding");
+ }
+ IdleServiceInfo serviceInfo = new IdleServiceInfo(info, componentName);
+ mIdleServices.put(componentName, serviceInfo);
+ mIdleServiceQueue.add(serviceInfo);
+ }
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "Idle service " + info.serviceInfo
+ + " does not have required permission; ignoring");
+ }
+ }
+ }
+ }
+ }
+
+ void startNextIdleServiceTm() {
+ mWakeLock.setWorkSource(mSystemWorkSource);
+
+ if (mLastIdler == null) {
+ // we've run the queue; nothing more to do until the next idle interval.
+ if (DEBUG) {
+ Slog.i(TAG, "Queue already drained; nothing more to do");
+ }
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.i(TAG, "startNextIdleService : last=" + mLastIdler + " cur=" + mCurrentIdler);
+ if (mIdleServiceQueue.size() > 0) {
+ int i = 0;
+ Slog.i(TAG, "Queue (" + mIdleServiceQueue.size() + "):");
+ for (IdleServiceInfo info : mIdleServiceQueue) {
+ Slog.i(TAG, " " + i + " : " + info);
+ i++;
+ }
+ }
+ }
+ if (mCurrentIdler != mLastIdler) {
+ if (mIdleServiceQueue.size() > 0) {
+ IdleServiceInfo target = mIdleServiceQueue.pop();
+ if (DEBUG) {
+ Slog.i(TAG, "starting next idle service " + target);
+ }
+ Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
+ idleIntent.setComponent(target.componentName);
+ mCurrentIdler = target;
+ ActiveTask task = new ActiveTask(target, VERB_BINDING);
+ scheduleOpTimeoutTm(task);
+ boolean bindOk = mContext.bindServiceAsUser(idleIntent, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY, UserHandle.OWNER);
+ if (!bindOk) {
+ if (DEBUG) {
+ Slog.w(TAG, "bindService() to " + target.componentName
+ + " failed");
+ }
+ } else {
+ mIdleServiceQueue.add(target); // at the end for next time
+ if (DEBUG) { Slog.i(TAG, "Attributing wakelock to target uid " + target.uid); }
+ mWakeLock.setWorkSource(new WorkSource(target.uid));
+ }
+ } else {
+ // Queue is empty but mLastIdler is non-null -- eeep. Clear *everything*
+ // and wind up until the next time around.
+ Slog.e(TAG, "Queue unexpectedly empty; resetting. last="
+ + mLastIdler + " cur=" + mCurrentIdler);
+ mHandler.removeMessages(MSG_TIMEOUT);
+ mPendingOperations.clear();
+ stopIdleMaintenanceTm();
+ }
+ } else {
+ // we've reached the place we started, so mark the queue as drained
+ if (DEBUG) {
+ Slog.i(TAG, "Reached end of queue.");
+ }
+ stopIdleMaintenanceTm();
+ }
+ }
+
+ void sendStartIdleTm(IdleServiceInfo who) {
+ ActiveTask task = new ActiveTask(who, VERB_IDLING);
+ scheduleOpTimeoutTm(task);
+ try {
+ who.service.startIdleMaintenance(mCallback, task.token);
+ } catch (RemoteException e) {
+ // We bound to it, but now we can't reach it. Bail and go on to the
+ // next service.
+ mContext.unbindService(mConnection);
+ if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
+ mHandler.removeMessages(MSG_TIMEOUT);
+ startNextIdleServiceTm();
+ }
+ }
+
+ void sendEndIdleTm(IdleServiceInfo who) {
+ ActiveTask task = new ActiveTask(who, VERB_ENDING);
+ scheduleOpTimeoutTm(task);
+ if (DEBUG) {
+ Slog.i(TAG, "Sending end-idle to " + who);
+ }
+ try {
+ who.service.stopIdleMaintenance(mCallback, task.token);
+ } catch (RemoteException e) {
+ // We bound to it, but now we can't reach it. Bail and go on to the
+ // next service.
+ mContext.unbindService(mConnection);
+ if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
+ mHandler.removeMessages(MSG_TIMEOUT);
+ startNextIdleServiceTm();
+ }
+ }
+
+ ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) {
+ Slog.i(TAG, "onServiceConnected(" + name + ")");
+ }
+ IdleServiceInfo info = mIdleServices.get(name);
+ if (info != null) {
+ // Bound! Cancel the bind timeout
+ mHandler.removeMessages(MSG_TIMEOUT);
+ // Now tell it to start its idle work
+ info.service = IIdleService.Stub.asInterface(service);
+ sendStartIdleTm(info);
+ } else {
+ // We bound to a service we don't know about. That's ungood.
+ Slog.e(TAG, "Connected to unexpected component " + name);
+ mContext.unbindService(this);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) {
+ Slog.i(TAG, "onServiceDisconnected(" + name + ")");
+ }
+ IdleServiceInfo who = mIdleServices.get(name);
+ if (who == mCurrentIdler) {
+ // Hm, okay; they didn't tell us they were finished but they
+ // went away. Crashed, probably. Oh well. They're gone, so
+ // we can't finish them cleanly; just force things along.
+ Slog.w(TAG, "Idler unexpectedly vanished: " + mCurrentIdler);
+ mContext.unbindService(this);
+ mHandler.removeMessages(MSG_TIMEOUT);
+ startNextIdleServiceTm();
+ } else {
+ // Not the current idler, so we don't interrupt our process...
+ if (DEBUG) {
+ Slog.w(TAG, "Disconnect of abandoned or unexpected service " + name);
+ }
+ }
+ }
+ };
+
+ // Schedules a timeout / end-of-work based on the task verb
+ void scheduleOpTimeoutTm(ActiveTask task) {
+ final long timeoutMillis = (task.verb == VERB_IDLING) ? IDLE_TIMESLICE : OP_TIMEOUT;
+ if (DEBUG) {
+ Slog.i(TAG, "Scheduling timeout (token " + task.token
+ + " : verb " + task.verb + ") for " + task + " in " + timeoutMillis);
+ }
+ mPendingOperations.put(task.token, task);
+ mHandler.removeMessages(MSG_TIMEOUT);
+ final Message msg = mHandler.obtainMessage(MSG_TIMEOUT, 0, task.token);
+ mHandler.sendMessageDelayed(msg, timeoutMillis);
+ }
+
+ // -------------------------------------------------------------------------------
public IdleMaintenanceService(Context context, BatteryService batteryService) {
mContext = context;
mBatteryService = batteryService;
@@ -111,9 +574,10 @@
mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mHandler = new Handler(mContext.getMainLooper());
+ mHandler = new IdleHandler(mContext.getMainLooper());
+ mCallback = new IdleCallback();
Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -159,26 +623,28 @@
mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
}
- private void updateIdleMaintenanceState(boolean noisy) {
+ private void updateIdleMaintenanceStateTm(boolean noisy) {
if (mIdleMaintenanceStarted) {
// Idle maintenance can be interrupted by user activity, or duration
// time out, or low battery.
- if (!lastUserActivityPermitsIdleMaintenanceRunning()
- || !batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) {
+ final boolean batteryOk
+ = batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning();
+ if (!lastUserActivityPermitsIdleMaintenanceRunning() || !batteryOk) {
unscheduleUpdateIdleMaintenanceState();
mIdleMaintenanceStarted = false;
- EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(),
- mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
- isBatteryCharging() ? 1 : 0);
- sendIdleMaintenanceEndIntent();
// We stopped since we don't have enough battery or timed out but the
// user is not using the device, so we should be able to run maintenance
// in the next maintenance window since the battery may be charged
// without interaction and the min interval between maintenances passed.
- if (!batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) {
+ if (!batteryOk) {
scheduleUpdateIdleMaintenanceState(
getNextIdleMaintenanceIntervalStartFromNow());
}
+
+ EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(),
+ mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
+ isBatteryCharging() ? 1 : 0);
+ scheduleIdleFinishTm();
}
} else if (deviceStatePermitsIdleMaintenanceStart(noisy)
&& lastUserActivityPermitsIdleMaintenanceStart(noisy)
@@ -191,7 +657,7 @@
mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
isBatteryCharging() ? 1 : 0);
mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
- sendIdleMaintenanceStartIntent();
+ startIdleMaintenanceTm();
} else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) {
if (lastRunPermitsIdleMaintenanceStart(noisy)) {
// The user does not use the device and we did not run maintenance in more
@@ -207,27 +673,57 @@
}
}
+ void startIdleMaintenanceTm() {
+ if (DEBUG) {
+ Slog.i(TAG, "*** Starting idle maintenance ***");
+ }
+ if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
+ mWakeLock.setWorkSource(mSystemWorkSource);
+ mWakeLock.acquire();
+ updateIdleServiceQueueTm();
+ mCurrentIdler = null;
+ mLastIdler = (mIdleServiceQueue.size() > 0) ? mIdleServiceQueue.peekLast() : null;
+ startNextIdleServiceTm();
+ }
+
+ // Start a graceful wind-down of the idle maintenance state: end the current idler
+ // and pretend that we've finished running the queue. If there's no current idler,
+ // this is a no-op.
+ void scheduleIdleFinishTm() {
+ if (mCurrentIdler != null) {
+ if (DEBUG) {
+ Slog.i(TAG, "*** Finishing idle maintenance ***");
+ }
+ mLastIdler = mCurrentIdler;
+ sendEndIdleTm(mCurrentIdler);
+ } else {
+ if (DEBUG) {
+ Slog.w(TAG, "Asked to finish idle maintenance but we're done already");
+ }
+ }
+ }
+
+ // Actual finalization of the idle maintenance sequence
+ void stopIdleMaintenanceTm() {
+ if (mLastIdler != null) {
+ if (DEBUG) {
+ Slog.i(TAG, "*** Idle maintenance shutdown ***");
+ }
+ mWakeLock.setWorkSource(mSystemWorkSource);
+ mLastIdler = mCurrentIdler = null;
+ updateIdleMaintenanceStateTm(false); // resets 'started' and schedules next window
+ mWakeLock.release();
+ } else {
+ Slog.e(TAG, "ERROR: idle shutdown but invariants not held. last=" + mLastIdler
+ + " cur=" + mCurrentIdler + " size=" + mIdleServiceQueue.size());
+ }
+ }
+
private long getNextIdleMaintenanceIntervalStartFromNow() {
return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS
- SystemClock.elapsedRealtime();
}
- private void sendIdleMaintenanceStartIntent() {
- mWakeLock.acquire();
- try {
- ActivityManagerNative.getDefault().performIdleMaintenance();
- } catch (RemoteException e) {
- }
- mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL,
- null, this, mHandler, Activity.RESULT_OK, null, null);
- }
-
- private void sendIdleMaintenanceEndIntent() {
- mWakeLock.acquire();
- mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceEndIntent, UserHandle.ALL,
- null, this, mHandler, Activity.RESULT_OK, null, null);
- }
-
private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
final int minBatteryLevel = isBatteryCharging()
? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
@@ -281,7 +777,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) {
- Log.i(LOG_TAG, intent.getAction());
+ Log.i(TAG, intent.getAction());
}
String action = intent.getAction();
if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
@@ -292,7 +788,7 @@
// next release. The only client for this for now is internal an holds
// a wake lock correctly.
if (mIdleMaintenanceStarted) {
- updateIdleMaintenanceState(false);
+ updateIdleMaintenanceStateTm(false);
}
} else if (Intent.ACTION_SCREEN_ON.equals(action)
|| Intent.ACTION_DREAMING_STOPPED.equals(action)) {
@@ -302,7 +798,7 @@
unscheduleUpdateIdleMaintenanceState();
// If the screen went on/stopped dreaming, we know the user is using the
// device which means that idle maintenance should be stopped if running.
- updateIdleMaintenanceState(false);
+ updateIdleMaintenanceStateTm(false);
} else if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_DREAMING_STARTED.equals(action)) {
mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
@@ -311,17 +807,12 @@
// this timeout elapses since the device may go to sleep by then.
scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
} else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
- updateIdleMaintenanceState(false);
+ updateIdleMaintenanceStateTm(false);
} else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) {
long now = SystemClock.elapsedRealtime() - 1;
mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START;
mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
- updateIdleMaintenanceState(true);
- } else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)
- || Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
- // We were holding a wake lock while broadcasting the idle maintenance
- // intents but now that we finished the broadcast release the wake lock.
- mWakeLock.release();
+ updateIdleMaintenanceStateTm(true);
}
}
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 816ae69..e6e4bca 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -107,6 +107,9 @@
class MountService extends IMountService.Stub
implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
+ // Static direct instance pointer for the tightly-coupled idle service to use
+ static MountService sSelf = null;
+
// TODO: listen for user creation/deletion
private static final boolean LOCAL_LOGD = false;
@@ -345,6 +348,7 @@
private static final int H_UNMOUNT_PM_DONE = 2;
private static final int H_UNMOUNT_MS = 3;
private static final int H_SYSTEM_READY = 4;
+ private static final int H_FSTRIM = 5;
private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
private static final int MAX_UNMOUNT_RETRIES = 4;
@@ -494,6 +498,24 @@
}
break;
}
+ case H_FSTRIM: {
+ waitForReady();
+ Slog.i(TAG, "Running fstrim idle maintenance");
+ try {
+ // This method must be run on the main (handler) thread,
+ // so it is safe to directly call into vold.
+ mConnector.execute("fstrim", "dotrim");
+ EventLogTags.writeFstrimStart(SystemClock.elapsedRealtime());
+ } catch (NativeDaemonConnectorException ndce) {
+ Slog.e(TAG, "Failed to run fstrim!");
+ }
+ // invoke the completion callback, if any
+ Runnable callback = (Runnable) msg.obj;
+ if (callback != null) {
+ callback.run();
+ }
+ break;
+ }
}
}
};
@@ -608,27 +630,6 @@
}
};
- private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- waitForReady();
- String action = intent.getAction();
- // Since fstrim will be run on a daily basis we do not expect
- // fstrim to be too long, so it is not interruptible. We will
- // implement interruption only in case we see issues.
- if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
- try {
- // This method runs on the handler thread,
- // so it is safe to directly call into vold.
- mConnector.execute("fstrim", "dotrim");
- EventLogTags.writeFstrimStart(SystemClock.elapsedRealtime());
- } catch (NativeDaemonConnectorException ndce) {
- Slog.e(TAG, "Failed to run fstrim!");
- }
- }
- }
- };
-
private final class MountServiceBinderListener implements IBinder.DeathRecipient {
final IMountServiceListener mListener;
@@ -646,6 +647,10 @@
}
}
+ void runIdleMaintenance(Runnable callback) {
+ mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
+ }
+
private void doShareUnshareVolume(String path, String method, boolean enable) {
// TODO: Add support for multiple share methods
if (!method.equals("ums")) {
@@ -1337,6 +1342,8 @@
* @param context Binder context for this service
*/
public MountService(Context context) {
+ sSelf = this;
+
mContext = context;
synchronized (mVolumesLock) {
@@ -1363,12 +1370,6 @@
mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);
}
- // Watch for idle maintenance changes
- IntentFilter idleMaintenanceFilter = new IntentFilter();
- idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
- mContext.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
- idleMaintenanceFilter, null, mHandler);
-
// Add OBB Action Handler to MountService thread.
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
new file mode 100644
index 0000000..8b19321
--- /dev/null
+++ b/services/core/java/com/android/server/MountServiceIdler.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.server;
+
+import android.app.maintenance.IdleService;
+import android.util.Slog;
+
+public class MountServiceIdler extends IdleService {
+ private static final String TAG = "MountServiceIdler";
+
+ private Runnable mFinishCallback = new Runnable() {
+ @Override
+ public void run() {
+ Slog.i(TAG, "Got mount service completion callback");
+ finishIdle();
+ }
+ };
+
+ @Override
+ public boolean onIdleStart() {
+ // The mount service will run an fstrim operation asynchronously
+ // on a designated separate thread, so we provide it with a callback
+ // that lets us cleanly end our idle timeslice. It's safe to call
+ // finishIdle() from any thread.
+ MountService ms = MountService.sSelf;
+ if (ms != null) {
+ ms.runIdleMaintenance(mFinishCallback);
+ }
+ return ms != null;
+ }
+
+ @Override
+ public void onIdleStop() {
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a21157f..8693c31 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3125,7 +3125,7 @@
}
}
int ret = pir.sendInner(0, fillInIntent, resolvedType, null, null,
- resultTo, resultWho, requestCode, flagsMask, flagsValues, options);
+ resultTo, resultWho, requestCode, flagsMask, flagsValues, options, null);
return ret;
}
@@ -3237,7 +3237,8 @@
final int startActivityInPackage(int uid, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int startFlags, Bundle options, int userId) {
+ String resultWho, int requestCode, int startFlags, Bundle options, int userId,
+ IActivityContainer container) {
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
false, true, "startActivityInPackage", null);
@@ -3245,7 +3246,7 @@
// TODO: Switch to user app stacks here.
int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags,
- null, null, null, null, options, userId, null);
+ null, null, null, null, options, userId, container);
return ret;
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 70d85fc..4a07256 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -738,6 +738,12 @@
mStackSupervisor.resumeTopActivitiesLocked();
return;
}
+
+ if (mActivityContainer.mParentActivity == null) {
+ // Top level stack, not a child. Look for child stacks.
+ mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping);
+ }
+
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
@@ -1282,6 +1288,13 @@
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+ ActivityRecord parent = mActivityContainer.mParentActivity;
+ if (parent != null && parent.state != ActivityState.RESUMED) {
+ // Do not resume this stack if its parent is not resumed.
+ // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
+ return false;
+ }
+
cancelInitializingActivities();
// Find the first activity that is not finishing.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6115f06..a33b0e5 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -277,6 +277,10 @@
// TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the
// top of all visible stacks.
boolean isFrontStack(ActivityStack stack) {
+ final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
+ if (parent != null) {
+ stack = parent.task.stack;
+ }
ArrayList<ActivityStack> stacks = stack.mStacks;
if (stacks != null && !stacks.isEmpty()) {
return stack == stacks.get(stacks.size() - 1);
@@ -510,6 +514,20 @@
return pausing;
}
+ void pauseChildStacks(ActivityRecord parent, boolean userLeaving, boolean uiSleeping) {
+ // TODO: Put all stacks in supervisor and iterate through them instead.
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = stacks.get(stackNdx);
+ if (stack.mResumedActivity != null &&
+ stack.mActivityContainer.mParentActivity == parent) {
+ stack.startPausingLocked(userLeaving, uiSleeping);
+ }
+ }
+ }
+ }
+
void reportActivityVisibleLocked(ActivityRecord r) {
for (int i = mWaitingActivityVisible.size()-1; i >= 0; i--) {
WaitResult w = mWaitingActivityVisible.get(i);
@@ -2915,7 +2933,7 @@
mStack.mStacks = activityDisplay.mStacks;
activityDisplay.attachActivities(mStack);
- mWindowManager.createStack(mStackId, activityDisplay.mDisplayId);
+ mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId);
}
@Override
@@ -2945,6 +2963,7 @@
mActivityDisplay = null;
mStack.mDisplayId = -1;
mStack.mStacks = null;
+ mWindowManager.detachStack(mStackId);
}
}
@@ -2957,7 +2976,7 @@
@Override
public final int startActivity(Intent intent) {
- mService.enforceNotIsolatedCaller("ActivityContainer");
+ mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
int userId = mService.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
// TODO: Switch to user app stacks here.
@@ -2971,20 +2990,40 @@
}
@Override
+ public final int startActivityIntentSender(IIntentSender intentSender) {
+ mService.enforceNotIsolatedCaller("ActivityContainer.startActivityIntentSender");
+
+ if (!(intentSender instanceof PendingIntentRecord)) {
+ throw new IllegalArgumentException("Bad PendingIntent object");
+ }
+
+ return ((PendingIntentRecord)intentSender).sendInner(0, null, null, null, null, null,
+ null, 0, 0, 0, null, this);
+ }
+
+ @Override
public IBinder asBinder() {
return this;
}
@Override
public void attachToSurface(Surface surface, int width, int height, int density) {
- synchronized (mService) {
- ActivityDisplay activityDisplay =
- new ActivityDisplay(surface, width, height, density);
- mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
- attachToDisplayLocked(activityDisplay);
+ mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface");
+
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService) {
+ ActivityDisplay activityDisplay =
+ new ActivityDisplay(surface, width, height, density);
+ mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
+ attachToDisplayLocked(activityDisplay);
+ mStack.resumeTopActivityLocked(null);
+ }
+ if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
+ + mActivityDisplay);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
- + mActivityDisplay);
}
ActivityStackSupervisor getOuter() {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 17f24a9..00fa216 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.app.ActivityManager;
+import android.app.IActivityContainer;
import android.content.IIntentSender;
import android.content.IIntentReceiver;
import android.app.PendingIntent;
@@ -190,13 +191,13 @@
public int send(int code, Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission) {
return sendInner(code, intent, resolvedType, finishedReceiver,
- requiredPermission, null, null, 0, 0, 0, null);
+ requiredPermission, null, null, 0, 0, 0, null, null);
}
int sendInner(int code, Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission,
IBinder resultTo, String resultWho, int requestCode,
- int flagsMask, int flagsValues, Bundle options) {
+ int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
synchronized(owner) {
if (!canceled) {
sent = true;
@@ -251,7 +252,7 @@
} else {
owner.startActivityInPackage(uid, key.packageName, finalIntent,
resolvedType, resultTo, resultWho, requestCode, 0,
- options, userId);
+ options, userId, container);
}
} catch (RuntimeException e) {
Slog.w(ActivityManagerService.TAG,
@@ -302,7 +303,8 @@
}
return ActivityManager.START_CANCELED;
}
-
+
+ @Override
protected void finalize() throws Throwable {
try {
if (!canceled) {
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 978d5b7..30eaf45 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -51,9 +51,9 @@
/** Owning stack */
final TaskStack mStack;
- DimLayer(WindowManagerService service, TaskStack stack) {
+ DimLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent) {
mStack = stack;
- mDisplayContent = stack.getDisplayContent();
+ mDisplayContent = displayContent;
final int displayId = mDisplayContent.getDisplayId();
if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
SurfaceControl.openTransaction();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0a070c1..9f45e88 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerService.TAG;
@@ -116,7 +115,7 @@
/**
* @param display May not be null.
- * @param service TODO(cmautner):
+ * @param service You know.
*/
DisplayContent(Display display, WindowManagerService service) {
mDisplay = display;
@@ -236,19 +235,16 @@
return count;
}
- /** Refer to {@link WindowManagerService#createStack(int, int)} */
- TaskStack createStack(int stackId) {
- if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId);
- TaskStack newStack = new TaskStack(mService, stackId, this);
- if (stackId == HOME_STACK_ID) {
+ /** Refer to {@link WindowManagerService#attachStack(int, int)} */
+ void attachStack(TaskStack stack) {
+ if (stack.mStackId == HOME_STACK_ID) {
if (mHomeStack != null) {
- throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
+ throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
}
- mHomeStack = newStack;
+ mHomeStack = stack;
}
- mStacks.add(newStack);
+ mStacks.add(stack);
layoutNeeded = true;
- return newStack;
}
void moveStack(TaskStack stack, boolean toTop) {
@@ -256,12 +252,15 @@
mStacks.add(toTop ? mStacks.size() : 0, stack);
}
- TaskStack removeStack(TaskStack stack) {
- mStacks.remove(stack);
- if (!mStacks.isEmpty()) {
- return mStacks.get(mStacks.size() - 1);
+ void detachStack(TaskStack stack) {
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final Task task = mTaskHistory.get(taskNdx);
+ if (task.mStack == stack) {
+ mService.tmpRemoveTaskWindowsLocked(task);
+ mTaskHistory.remove(taskNdx);
+ }
}
- return null;
+ mStacks.remove(stack);
}
/**
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 87cabc9..ca9076f 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -293,7 +293,11 @@
// !!! FIXME: put all this heavy stuff onto the mH looper, as well as
// the actual drag event dispatch stuff in the dragstate
- Display display = callingWin.mDisplayContent.getDisplay();
+ final DisplayContent displayContent = callingWin.getDisplayContent();
+ if (displayContent == null) {
+ return false;
+ }
+ Display display = displayContent.getDisplay();
mService.mDragState.register(display);
mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a1704a6..44f2596 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -45,7 +45,6 @@
if (mAppTokens.size() == 0) {
EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
"removeAppToken: last token");
- mStack.removeTask(this);
return true;
}
return false;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index aa6b0c9..1ada6c2 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -41,7 +41,7 @@
private final WindowManagerService mService;
/** The display this stack sits under. */
- private final DisplayContent mDisplayContent;
+ private DisplayContent mDisplayContent;
/** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
* mTaskHistory in the ActivityStack with the same mStackId */
@@ -52,13 +52,13 @@
Rect mBounds = new Rect();
/** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
- final DimLayer mDimLayer;
+ DimLayer mDimLayer;
/** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */
WindowStateAnimator mDimWinAnimator;
/** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
- final DimLayer mAnimationBackgroundSurface;
+ DimLayer mAnimationBackgroundSurface;
/** The particular window with an Animation with non-zero background color. */
WindowStateAnimator mAnimationBackgroundAnimator;
@@ -67,12 +67,9 @@
* then stop any dimming. */
boolean mDimmingTag;
- TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) {
+ TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
- mDisplayContent = displayContent;
- mDimLayer = new DimLayer(service, this);
- mAnimationBackgroundSurface = new DimLayer(service, this);
// TODO: remove bounds from log, they are always 0.
EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
mBounds.right, mBounds.bottom);
@@ -121,12 +118,16 @@
}
void getBounds(Rect out) {
- if (mBounds.isEmpty()) {
- mDisplayContent.getLogicalDisplayRect(out);
+ if (mDisplayContent != null) {
+ if (mBounds.isEmpty()) {
+ mDisplayContent.getLogicalDisplayRect(out);
+ } else {
+ out.set(mBounds);
+ }
+ out.intersect(mDisplayContent.mContentRect);
} else {
out.set(mBounds);
}
- out.intersect(mDisplayContent.mContentRect);
}
boolean isFullscreen() {
@@ -198,22 +199,37 @@
void removeTask(Task task) {
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
mTasks.remove(task);
- mDisplayContent.removeTask(task);
- if (mTasks.isEmpty()) {
- mDisplayContent.moveStack(this, false);
+ if (mDisplayContent != null) {
+ mDisplayContent.removeTask(task);
+ if (mTasks.isEmpty()) {
+ mDisplayContent.moveStack(this, false);
+ }
+ mDisplayContent.layoutNeeded = true;
}
- mDisplayContent.layoutNeeded = true;
}
- int remove() {
- mAnimationBackgroundSurface.destroySurface();
- mDimLayer.destroySurface();
- EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
- TaskStack next = mDisplayContent.removeStack(this);
- if (next != null) {
- return next.mStackId;
+ void attachDisplayContent(DisplayContent displayContent) {
+ if (mDisplayContent != null) {
+ throw new IllegalStateException("attachDisplayContent: Already attached");
}
- return -1;
+
+ mDisplayContent = displayContent;
+ mDimLayer = new DimLayer(mService, this, displayContent);
+ mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
+
+ for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
+ Task task = mTasks.get(taskNdx);
+ displayContent.addTask(task, true);
+ }
+ }
+
+ void detach() {
+ EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
+ mAnimationBackgroundSurface.destroySurface();
+ mAnimationBackgroundSurface = null;
+ mDimLayer.destroySurface();
+ mDimLayer = null;
+ mDisplayContent = null;
}
void resetAnimationBackgroundAnimator() {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 91f15f3..b4285c6 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -642,11 +642,16 @@
}
int getPendingLayoutChanges(final int displayId) {
+ if (displayId < 0) {
+ return 0;
+ }
return mService.getDisplayContentLocked(displayId).pendingLayoutChanges;
}
void setPendingLayoutChanges(final int displayId, final int changes) {
- mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+ if (displayId >= 0) {
+ mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+ }
}
void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
@@ -655,7 +660,7 @@
WindowList windows = appAnimator.mAppToken.allAppWindows;
for (int i = windows.size() - 1; i >= 0; i--) {
final int displayId = windows.get(i).getDisplayId();
- if (displays.indexOfKey(displayId) < 0) {
+ if (displayId >= 0 && displays.indexOfKey(displayId) < 0) {
setPendingLayoutChanges(displayId, changes);
if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
@@ -676,10 +681,15 @@
}
void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
- getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+ if (displayId >= 0) {
+ getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+ }
}
ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
+ if (displayId < 0) {
+ return null;
+ }
return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6c7fb26..5387436 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -155,8 +155,7 @@
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
- implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
- DisplayManager.DisplayListener {
+ implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
@@ -269,10 +268,10 @@
// Default input dispatching timeout in nanoseconds.
static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
- /** Minimum value for createStack and resizeStack weight value */
+ /** Minimum value for attachStack and resizeStack weight value */
public static final float STACK_WEIGHT_MIN = 0.2f;
- /** Maximum value for createStack and resizeStack weight value */
+ /** Maximum value for attachStack and resizeStack weight value */
public static final float STACK_WEIGHT_MAX = 0.8f;
static final int UPDATE_FOCUS_NORMAL = 0;
@@ -742,7 +741,6 @@
mFxSession = new SurfaceSession();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
- mDisplayManager.registerDisplayListener(this, null);
Display[] displays = mDisplayManager.getDisplays();
for (Display display : displays) {
createDisplayContentLocked(display);
@@ -874,7 +872,7 @@
final int count = token.windows.size();
for (int i = 0; i < count; i++) {
final WindowState win = token.windows.get(i);
- if (win.mDisplayContent == displayContent) {
+ if (win.getDisplayContent() == displayContent) {
windowList.add(win);
}
}
@@ -905,7 +903,7 @@
private int addAppWindowToListLocked(final WindowState win) {
final IWindow client = win.mClient;
final WindowToken token = win.mToken;
- final DisplayContent displayContent = win.mDisplayContent;
+ final DisplayContent displayContent = win.getDisplayContent();
final WindowList windows = win.getWindowList();
final int N = windows.size();
@@ -1082,7 +1080,7 @@
private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
final WindowToken token = win.mToken;
- final DisplayContent displayContent = win.mDisplayContent;
+ final DisplayContent displayContent = win.getDisplayContent();
final WindowState attached = win.mAttachedWindow;
WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
@@ -2016,7 +2014,10 @@
}
void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
- final DisplayContent displayContent = changingTarget.mDisplayContent;
+ final DisplayContent displayContent = changingTarget.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
@@ -2076,7 +2077,10 @@
void updateWallpaperVisibilityLocked() {
final boolean visible = isWallpaperVisible(mWallpaperTarget);
- final DisplayContent displayContent = mWallpaperTarget.mDisplayContent;
+ final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
@@ -2428,7 +2432,10 @@
//Slog.i(TAG, "*** Running exit animation...");
win.mExiting = true;
win.mRemoveOnExit = true;
- win.mDisplayContent.layoutNeeded = true;
+ final DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
false /*updateInputWindows*/);
performLayoutAndPlaceSurfacesLocked();
@@ -2485,8 +2492,6 @@
mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
}
- final WindowList windows = win.getWindowList();
- windows.remove(win);
mPendingRemove.remove(win);
mResizingWindows.remove(win);
mWindowsChanged = true;
@@ -2541,12 +2546,19 @@
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
- if (!mInLayout) {
- assignLayersLocked(windows);
- win.mDisplayContent.layoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
- if (win.mAppToken != null) {
- win.mAppToken.updateReportedVisibilityLocked();
+ final WindowList windows = win.getWindowList();
+ if (windows != null) {
+ windows.remove(win);
+ if (!mInLayout) {
+ assignLayersLocked(windows);
+ final DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
+ performLayoutAndPlaceSurfacesLocked();
+ if (win.mAppToken != null) {
+ win.mAppToken.updateReportedVisibilityLocked();
+ }
}
}
@@ -2621,7 +2633,10 @@
w.mGivenVisibleInsets.scale(w.mGlobalScale);
w.mGivenTouchableRegion.scale(w.mGlobalScale);
}
- w.mDisplayContent.layoutNeeded = true;
+ final DisplayContent displayContent = w.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
performLayoutAndPlaceSurfacesLocked();
}
}
@@ -2707,7 +2722,12 @@
mTmpFloats[Matrix.MSKEW_X] = dsdy;
mTmpFloats[Matrix.MSCALE_Y] = dtdy;
matrix.setValues(mTmpFloats);
- final DisplayInfo displayInfo = window.mDisplayContent.getDisplayInfo();
+ final DisplayContent displayContent = window.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+
+ final DisplayInfo displayInfo = window.getDisplayContent().getDisplayInfo();
final RectF dispRect = new RectF(0, 0,
displayInfo.logicalWidth, displayInfo.logicalHeight);
matrix.mapRect(dispRect);
@@ -2716,7 +2736,7 @@
window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top,
(int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE);
window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
- window.mDisplayContent.layoutNeeded = true;
+ displayContent.layoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
@@ -2997,7 +3017,10 @@
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
- win.mDisplayContent.layoutNeeded = true;
+ final DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
configChanged = updateOrientationFromAppTokensLocked(false);
performLayoutAndPlaceSurfacesLocked();
@@ -3091,7 +3114,10 @@
getDefaultDisplayContentLocked().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
- win.mDisplayContent.layoutNeeded = true;
+ final DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
requestTraversalLocked();
}
}
@@ -3349,7 +3375,7 @@
for (int i=0; i<N; i++) {
WindowState win = wtoken.windows.get(i);
- displayContent = win.mDisplayContent;
+ displayContent = win.getDisplayContent();
if (win.mWinAnimator.isAnimating()) {
delayed = true;
@@ -3364,7 +3390,9 @@
WindowManagerPolicy.TRANSIT_EXIT);
}
changed = true;
- displayContent.layoutNeeded = true;
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
}
}
@@ -3377,7 +3405,9 @@
}
if (delayed) {
- displayContent.mExitingTokens.add(wtoken);
+ if (displayContent != null) {
+ displayContent.mExitingTokens.add(wtoken);
+ }
} else if (wtoken.windowType == TYPE_WALLPAPER) {
mWallpaperTokens.remove(wtoken);
}
@@ -3473,8 +3503,8 @@
Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
return;
}
- Task oldTask = mTaskIdToTask.get(atoken.groupId);
- oldTask.removeAppToken(atoken);
+ final Task oldTask = mTaskIdToTask.get(atoken.groupId);
+ removeAppFromTask(atoken);
atoken.groupId = groupId;
Task newTask = mTaskIdToTask.get(groupId);
@@ -3767,7 +3797,10 @@
if (mFocusedApp != null) {
Task task = mTaskIdToTask.get(mFocusedApp.groupId);
stack = task.mStack;
- task.getDisplayContent().setTouchExcludeRegion(stack);
+ final DisplayContent displayContent = task.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.setTouchExcludeRegion(stack);
+ }
} else {
stack = null;
}
@@ -4224,7 +4257,10 @@
}
}
changed = true;
- win.mDisplayContent.layoutNeeded = true;
+ final DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
}
} else if (win.isVisibleNow()) {
if (!runningAppAnimation) {
@@ -4238,7 +4274,10 @@
}
}
changed = true;
- win.mDisplayContent.layoutNeeded = true;
+ final DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
}
}
@@ -4386,7 +4425,10 @@
}
w.mLastFreezeDuration = 0;
unfrozeWindows = true;
- w.mDisplayContent.layoutNeeded = true;
+ final DisplayContent displayContent = w.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
}
}
if (force || unfrozeWindows) {
@@ -4480,6 +4522,14 @@
}
}
+ void removeAppFromTask(AppWindowToken wtoken) {
+ final Task task = mTaskIdToTask.get(wtoken.groupId);
+ if (task != null && task.removeAppToken(wtoken)) {
+ task.mStack.removeTask(task);
+ mTaskIdToTask.delete(wtoken.groupId);
+ }
+ }
+
@Override
public void removeAppToken(IBinder token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4514,7 +4564,7 @@
+ " animating=" + wtoken.mAppAnimator.animating);
final Task task = mTaskIdToTask.get(wtoken.groupId);
DisplayContent displayContent = task.getDisplayContent();
- if (delayed) {
+ if (displayContent != null && delayed) {
// set the token aside because it has an active animation to be finished
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
"removeAppToken make exiting: " + wtoken);
@@ -4529,9 +4579,8 @@
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
"removeAppToken: " + wtoken);
- if (task.removeAppToken(wtoken)) {
- mTaskIdToTask.delete(wtoken.groupId);
- }
+ removeAppFromTask(wtoken);
+
wtoken.removed = true;
if (wtoken.startingData != null) {
startingToken = wtoken;
@@ -4566,13 +4615,15 @@
mH.sendMessage(m);
}
}
+
private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
- final int NW = token.windows.size();
+ WindowList windows = token.windows;
+ final int NW = windows.size();
if (NW > 0) {
mWindowsChanged = true;
}
- for (int i=0; i<NW; i++) {
- WindowState win = token.windows.get(i);
+ for (int i = 0; i < NW; i++) {
+ WindowState win = windows.get(i);
if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
win.getWindowList().remove(win);
int j = win.mChildWindows.size();
@@ -4605,12 +4656,13 @@
}
void dumpWindowsLocked() {
- int i = 0;
final int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+ Slog.v(TAG, " Display #" + displayContent.getDisplayId());
+ final WindowList windows = displayContent.getWindowList();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- Slog.v(TAG, " #" + i++ + ": " + windows.get(winNdx));
+ Slog.v(TAG, " #" + winNdx + ": " + windows.get(winNdx));
}
}
}
@@ -4722,23 +4774,28 @@
final int NW = token.windows.size();
for (int i=0; i<NW; i++) {
final WindowState win = token.windows.get(i);
- if (win.mDisplayContent == displayContent) {
+ final DisplayContent winDisplayContent = win.getDisplayContent();
+ if (winDisplayContent == displayContent || winDisplayContent == null) {
+ win.mDisplayContent = displayContent;
index = reAddWindowLocked(index, win);
}
}
return index;
}
+ void tmpRemoveTaskWindowsLocked(Task task) {
+ AppTokenList tokens = task.mAppTokens;
+ for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+ tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
+ }
+ }
+
void moveStackWindowsLocked(DisplayContent displayContent) {
// First remove all of the windows from the list.
final ArrayList<Task> tasks = displayContent.getTasks();
final int numTasks = tasks.size();
for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
- AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- final int numTokens = tokens.size();
- for (int tokenNdx = numTokens - 1; tokenNdx >= 0; --tokenNdx) {
- tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
- }
+ tmpRemoveTaskWindowsLocked(tasks.get(taskNdx));
}
// And now add them back at the correct place.
@@ -4822,15 +4879,25 @@
* @param stackId The unique identifier of the new stack.
* @param displayId The unique identifier of the DisplayContent.
*/
- public void createStack(int stackId, int displayId) {
+ public void attachStack(int stackId, int displayId) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
final DisplayContent displayContent = mDisplayContents.get(displayId);
if (displayContent != null) {
- TaskStack stack = displayContent.createStack(stackId);
- mStackIdToStack.put(stackId, stack);
- performLayoutAndPlaceSurfacesLocked();
+ TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack == null) {
+ if (DEBUG_STACK) Slog.d(TAG, "attachStack: stackId=" + stackId);
+ stack = new TaskStack(this, stackId);
+ mStackIdToStack.put(stackId, stack);
+ }
+ stack.attachDisplayContent(displayContent);
+ displayContent.attachStack(stack);
+ moveStackWindowsLocked(displayContent);
+ final WindowList windows = displayContent.getWindowList();
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ windows.get(winNdx).reportResized();
+ }
}
}
} finally {
@@ -4838,6 +4905,19 @@
}
}
+ public void detachStack(int stackId) {
+ synchronized (mWindowMap) {
+ TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack != null) {
+ final DisplayContent displayContent = stack.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.detachStack(stack);
+ stack.detach();
+ }
+ }
+ }
+ }
+
public void removeTask(int taskId) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
@@ -7888,7 +7968,6 @@
}
final void rebuildAppWindowListLocked() {
- // TODO: Multidisplay, when ActivityStacks and tasks exist on more than one display.
rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
}
@@ -7953,7 +8032,8 @@
i -= lastBelow;
if (i != numRemoved) {
- Slog.w(TAG, "Rebuild removed " + numRemoved + " windows but added " + i,
+ Slog.w(TAG, "On display=" + displayContent.getDisplayId() + " Rebuild removed " +
+ numRemoved + " windows but added " + i,
new RuntimeException("here").fillInStackTrace());
for (i=0; i<numRemoved; i++) {
WindowState ws = mRebuildTmp[i];
@@ -8763,8 +8843,8 @@
if (canBeSeen) {
// This function assumes that the contents of the default display are
// processed first before secondary displays.
- final DisplayContent displayContent = w.mDisplayContent;
- if (displayContent.isDefaultDisplay) {
+ final DisplayContent displayContent = w.getDisplayContent();
+ if (displayContent != null && displayContent.isDefaultDisplay) {
// While a dream or keyguard is showing, obscure ordinary application
// content on secondary displays (by forcibly enabling mirroring unless
// there is other content we want to show) but still allow opaque
@@ -8773,8 +8853,9 @@
mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
}
mInnerFields.mDisplayHasContent = true;
- } else if (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
- || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG)) {
+ } else if (displayContent != null &&
+ (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
+ || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG))) {
// Allow full screen keyguard presentation dialogs to be seen.
mInnerFields.mDisplayHasContent = true;
}
@@ -9199,56 +9280,22 @@
continue;
}
final WindowStateAnimator winAnimator = win.mWinAnimator;
- try {
- if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Reporting new frame to " + win + ": " + win.mCompatFrame);
- int diff = 0;
- boolean configChanged = win.isConfigChanged();
- if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
- && configChanged) {
- Slog.i(TAG, "Sending new config to window " + win + ": "
- + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
- + " / " + mCurConfiguration + " / 0x"
- + Integer.toHexString(diff));
- }
- win.setConfiguration(mCurConfiguration);
- if (DEBUG_ORIENTATION &&
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
- TAG, "Resizing " + win + " WITH DRAW PENDING");
- final IWindow client = win.mClient;
- final Rect frame = win.mFrame;
- final Rect overscanInsets = win.mLastOverscanInsets;
- final Rect contentInsets = win.mLastContentInsets;
- final Rect visibleInsets = win.mLastVisibleInsets;
- final boolean reportDraw
- = winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
- final Configuration newConfig = configChanged ? win.mConfiguration : null;
- if (win.mClient instanceof IWindow.Stub) {
- // To prevent deadlock simulate one-way call if win.mClient is a local object.
- mH.post(new Runnable() {
- @Override
- public void run() {
- try {
- client.resized(frame, overscanInsets, contentInsets,
- visibleInsets, reportDraw, newConfig);
- } catch (RemoteException e) {
- // Not a remote call, RemoteException won't be raised.
- }
- }
- });
- } else {
- client.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
- newConfig);
- }
- win.mOverscanInsetsChanged = false;
- win.mContentInsetsChanged = false;
- win.mVisibleInsetsChanged = false;
- winAnimator.mSurfaceResized = false;
- } catch (RemoteException e) {
- win.mOrientationChanging = false;
- win.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- - mDisplayFreezeTime);
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+ "Reporting new frame to " + win + ": " + win.mCompatFrame);
+ int diff = 0;
+ boolean configChanged = win.isConfigChanged();
+ if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
+ && configChanged) {
+ Slog.i(TAG, "Sending new config to window " + win + ": "
+ + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
+ + " / " + mCurConfiguration + " / 0x"
+ + Integer.toHexString(diff));
}
+ win.setConfiguration(mCurConfiguration);
+ if (DEBUG_ORIENTATION &&
+ winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
+ TAG, "Resizing " + win + " WITH DRAW PENDING");
+ win.reportResized();
mResizingWindows.remove(i);
}
@@ -9309,10 +9356,7 @@
token.mAppAnimator.animating = false;
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
"performLayout: App token exiting now removed" + token);
- final Task task = mTaskIdToTask.get(token.groupId);
- if (task != null && task.removeAppToken(token)) {
- mTaskIdToTask.delete(token.groupId);
- }
+ removeAppFromTask(token);
exitingAppTokens.remove(i);
}
}
@@ -9393,8 +9437,9 @@
for (i = 0; i < N; i++) {
WindowState w = mPendingRemoveTmp[i];
removeWindowInnerLocked(w.mSession, w);
- if (!displayList.contains(w.mDisplayContent)) {
- displayList.add(w.mDisplayContent);
+ final DisplayContent displayContent = w.getDisplayContent();
+ if (displayContent != null && !displayList.contains(displayContent)) {
+ displayList.add(displayContent);
}
}
@@ -10765,7 +10810,6 @@
return displayContent != null ? displayContent.getWindowList() : null;
}
- @Override
public void onDisplayAdded(int displayId) {
mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
}
@@ -10780,7 +10824,6 @@
}
}
- @Override
public void onDisplayRemoved(int displayId) {
mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
}
@@ -10793,16 +10836,10 @@
if (displayId == Display.DEFAULT_DISPLAY) {
unregisterPointerEventListener(displayContent.mTapDetector);
}
- WindowList windows = displayContent.getWindowList();
- while (!windows.isEmpty()) {
- final WindowState win = windows.get(windows.size() - 1);
- removeWindowLocked(win.mSession, win);
- }
}
mAnimator.removeDisplayLocked(displayId);
}
- @Override
public void onDisplayChanged(int displayId) {
mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 77a36b8..2f778b1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -29,7 +29,9 @@
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import android.app.AppOpsManager;
+import android.os.Debug;
import android.os.RemoteCallbackList;
+import android.os.SystemClock;
import android.util.TimeUtils;
import android.view.IWindowFocusObserver;
import android.view.IWindowId;
@@ -593,9 +595,12 @@
}
if (mIsWallpaper && (fw != mFrame.width() || fh != mFrame.height())) {
- final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
- mService.updateWallpaperOffsetLocked(this,
- displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+ final DisplayContent displayContent = getDisplayContent();
+ if (displayContent != null) {
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ mService.updateWallpaperOffsetLocked(this,
+ displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+ }
}
if (DEBUG_LAYOUT || WindowManagerService.localLOGV) Slog.v(TAG,
@@ -708,8 +713,16 @@
return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged;
}
+ public DisplayContent getDisplayContent() {
+ return mAppToken == null ? mDisplayContent : getStack().getDisplayContent();
+ }
+
public int getDisplayId() {
- return mDisplayContent.getDisplayId();
+ final DisplayContent displayContent = getDisplayContent();
+ if (displayContent == null) {
+ return -1;
+ }
+ return displayContent.getDisplayId();
}
TaskStack getStack() {
@@ -722,7 +735,8 @@
}
Slog.e(TAG, "getStack: mStack null for task=" + task);
} else {
- Slog.e(TAG, "getStack: couldn't find taskId=" + wtoken.groupId);
+ Slog.e(TAG, "getStack: " + this + " couldn't find taskId=" + wtoken.groupId
+ + " Callers=" + Debug.getCallers(4));
}
}
return mDisplayContent.getHomeStack();
@@ -1196,7 +1210,12 @@
@Override
public boolean isDefaultDisplay() {
- return mDisplayContent.isDefaultDisplay;
+ final DisplayContent displayContent = getDisplayContent();
+ if (displayContent == null) {
+ // Only a window that was on a non-default display can be detached from it.
+ return false;
+ }
+ return getDisplayContent().isDefaultDisplay;
}
public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
@@ -1213,7 +1232,11 @@
&& win.mAppToken != null && win.mAppToken.showWhenLocked) {
// Save some cycles by not calling getDisplayInfo unless it is an application
// window intended for all users.
- final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo();
+ final DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent == null) {
+ return true;
+ }
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (win.mFrame.left <= 0 && win.mFrame.top <= 0
&& win.mFrame.right >= displayInfo.appWidth
&& win.mFrame.bottom >= displayInfo.appHeight) {
@@ -1255,7 +1278,8 @@
}
WindowList getWindowList() {
- return mDisplayContent.getWindowList();
+ final DisplayContent displayContent = getDisplayContent();
+ return displayContent == null ? null : displayContent.getWindowList();
}
/**
@@ -1284,6 +1308,43 @@
}
}
+ void reportResized() {
+ try {
+ final Rect frame = mFrame;
+ final Rect overscanInsets = mLastOverscanInsets;
+ final Rect contentInsets = mLastContentInsets;
+ final Rect visibleInsets = mLastVisibleInsets;
+ final boolean reportDraw
+ = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
+ final Configuration newConfig = isConfigChanged() ? mConfiguration : null;
+ if (mClient instanceof IWindow.Stub) {
+ // To prevent deadlock simulate one-way call if win.mClient is a local object.
+ mService.mH.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mClient.resized(frame, overscanInsets, contentInsets,
+ visibleInsets, reportDraw, newConfig);
+ } catch (RemoteException e) {
+ // Not a remote call, RemoteException won't be raised.
+ }
+ }
+ });
+ } else {
+ mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
+ newConfig);
+ }
+ mOverscanInsetsChanged = false;
+ mContentInsetsChanged = false;
+ mVisibleInsetsChanged = false;
+ mWinAnimator.mSurfaceResized = false;
+ } catch (RemoteException e) {
+ mOrientationChanging = false;
+ mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+ - mService.mDisplayFreezeTime);
+ }
+ }
+
public void registerFocusObserver(IWindowFocusObserver observer) {
synchronized(mService.mWindowMap) {
if (mFocusCallbacks == null) {
@@ -1308,7 +1369,7 @@
}
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
- pw.print(prefix); pw.print("mDisplayId="); pw.print(mDisplayContent.getDisplayId());
+ pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
pw.print(" mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c405170..76e885f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -150,8 +150,6 @@
int mAttrFlags;
int mAttrType;
- final int mLayerStack;
-
public WindowStateAnimator(final WindowState win) {
final WindowManagerService service = win.mService;
@@ -159,7 +157,7 @@
mAnimator = service.mAnimator;
mPolicy = service.mPolicy;
mContext = service.mContext;
- final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo();
+ final DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo();
mAnimDw = displayInfo.appWidth;
mAnimDh = displayInfo.appHeight;
@@ -171,7 +169,6 @@
mAttrFlags = win.mAttrs.flags;
mAttrType = win.mAttrs.type;
mIsWallpaper = win.mIsWallpaper;
- mLayerStack = win.mDisplayContent.getDisplay().getLayerStack();
}
public void setAnimation(Animation anim) {
@@ -243,7 +240,8 @@
// Save the animation state as it was before this step so WindowManagerService can tell if
// we just started or just stopped animating by comparing mWasAnimating with isAnimating().
mWasAnimating = mAnimating;
- if (mService.okToDisplay()) {
+ final DisplayContent displayContent = mWin.getDisplayContent();
+ if (displayContent != null && mService.okToDisplay()) {
// We will run animations as long as the display isn't frozen.
if (mWin.isDrawnLw() && mAnimation != null) {
@@ -258,7 +256,7 @@
" scale=" + mService.mWindowAnimationScale);
mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
mAnimDw, mAnimDh);
- final DisplayInfo displayInfo = mWin.mDisplayContent.getDisplayInfo();
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
mAnimDw = displayInfo.appWidth;
mAnimDh = displayInfo.appHeight;
mAnimation.setStartTime(currentTime);
@@ -337,7 +335,9 @@
+ mWin.mPolicyVisibilityAfterAnim);
}
mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim;
- mWin.mDisplayContent.layoutNeeded = true;
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
if (!mWin.mPolicyVisibility) {
if (mService.mCurrentFocus == mWin) {
if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
@@ -363,11 +363,13 @@
} else if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
// Upon completion of a not-visible to visible status bar animation a relayout is
// required.
- mWin.mDisplayContent.layoutNeeded = true;
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
}
finishExit();
- final int displayId = mWin.mDisplayContent.getDisplayId();
+ final int displayId = mWin.getDisplayId();
mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats(
"WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
@@ -732,7 +734,10 @@
mSurfaceY = mWin.mFrame.top + mWin.mYOffset;
mSurfaceControl.setPosition(mSurfaceX, mSurfaceY);
mSurfaceLayer = mAnimLayer;
- mSurfaceControl.setLayerStack(mLayerStack);
+ final DisplayContent displayContent = mWin.getDisplayContent();
+ if (displayContent != null) {
+ mSurfaceControl.setLayerStack(displayContent.getDisplay().getLayerStack());
+ }
mSurfaceControl.setLayer(mAnimLayer);
mSurfaceControl.setAlpha(0);
mSurfaceShown = false;
@@ -921,8 +926,7 @@
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
//TODO (multidisplay): Magnification is supported only for the default display.
- if (mService.mDisplayMagnifier != null
- && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
MagnificationSpec spec = mService.mDisplayMagnifier
.getMagnificationSpecForWindowLocked(mWin);
if (spec != null && !spec.isNop()) {
@@ -1002,7 +1006,7 @@
&& mWin.mBaseLayer < mAnimator.mAboveUniverseLayer);
MagnificationSpec spec = null;
//TODO (multidisplay): Magnification is supported only for the default display.
- if (mService.mDisplayMagnifier != null && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
spec = mService.mDisplayMagnifier.getMagnificationSpecForWindowLocked(mWin);
}
if (applyUniverseTransformation || spec != null) {
@@ -1080,7 +1084,11 @@
void updateSurfaceWindowCrop(final boolean recoveringMemory) {
final WindowState w = mWin;
- DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
+ final DisplayContent displayContent = w.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+ DisplayInfo displayInfo = displayContent.getDisplayInfo();
// Need to recompute a new system decor rect each time.
if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
@@ -1181,8 +1189,7 @@
"SIZE " + width + "x" + height, null);
mSurfaceResized = true;
mSurfaceControl.setSize(width, height);
- final int displayId = w.mDisplayContent.getDisplayId();
- mAnimator.setPendingLayoutChanges(displayId,
+ mAnimator.setPendingLayoutChanges(w.getDisplayId(),
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
w.getStack().startDimmingIfNeeded(this);
@@ -1444,7 +1451,10 @@
// do a layout. If called from within the transaction
// loop, this will cause it to restart with a new
// layout.
- c.mDisplayContent.layoutNeeded = true;
+ final DisplayContent displayContent = c.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.layoutNeeded = true;
+ }
}
}
}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index bfa0942..b5e4eef 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -76,7 +76,7 @@
return mRegistered;
}
/** @hide */
- public void setRegisterd(boolean registered) {
+ public void setRegistered(boolean registered) {
mRegistered = registered;
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 022bf12..d34c55c 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -275,7 +275,7 @@
* @param otaspMode is integer <code>OTASP_UNKNOWN=1<code>
* means the value is currently unknown and the system should wait until
* <code>OTASP_NEEDED=2<code> or <code>OTASP_NOT_NEEDED=3<code> is received before
- * making the decisision to perform OTASP or not.
+ * making the decision to perform OTASP or not.
*
* @hide
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a785bac..3d416fb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -23,7 +23,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.telephony.Rlog;
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ITelephony;
@@ -433,7 +432,7 @@
case RILConstants.NETWORK_MODE_GSM_UMTS:
case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
case RILConstants.NETWORK_MODE_LTE_WCDMA:
- case RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA:
+ case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
return PhoneConstants.PHONE_TYPE_GSM;
// Use CDMA Phone for the global mode including CDMA
@@ -1258,7 +1257,7 @@
* At registration, and when a specified telephony state
* changes, the telephony manager invokes the appropriate
* callback method on the listener object and passes the
- * current (udpated) values.
+ * current (updated) values.
* <p>
* To unregister a listener, pass the listener object and set the
* events argument to
@@ -1480,7 +1479,7 @@
*
* Input parameters equivalent to TS 27.007 AT+CGLA command.
*
- * @param channel is the channel id to be closed as retruned by a successful
+ * @param channel is the channel id to be closed as returned by a successful
* iccOpenLogicalChannel.
* @param cla Class of the APDU command.
* @param instruction Instruction of the APDU command.
@@ -1502,4 +1501,102 @@
}
return "";
}
+
+ /**
+ * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}.
+ * Used for device configuration by some CDMA operators.
+ *
+ * @param itemID the ID of the item to read.
+ * @return the NV item as a String, or null on any failure.
+ * @hide
+ */
+ public String nvReadItem(int itemID) {
+ try {
+ return getITelephony().nvReadItem(itemID);
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "nvReadItem RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "nvReadItem NPE", ex);
+ }
+ return "";
+ }
+
+
+ /**
+ * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}.
+ * Used for device configuration by some CDMA operators.
+ *
+ * @param itemID the ID of the item to read.
+ * @param itemValue the value to write, as a String.
+ * @return true on success; false on any failure.
+ * @hide
+ */
+ public boolean nvWriteItem(int itemID, String itemValue) {
+ try {
+ return getITelephony().nvWriteItem(itemID, itemValue);
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "nvWriteItem RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "nvWriteItem NPE", ex);
+ }
+ return false;
+ }
+
+ /**
+ * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
+ * Used for device configuration by some CDMA operators.
+ *
+ * @param preferredRoamingList byte array containing the new PRL.
+ * @return true on success; false on any failure.
+ * @hide
+ */
+ public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
+ try {
+ return getITelephony().nvWriteCdmaPrl(preferredRoamingList);
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "nvWriteCdmaPrl RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "nvWriteCdmaPrl NPE", ex);
+ }
+ return false;
+ }
+
+ /**
+ * Perform the specified type of NV config reset.
+ * Used for device configuration by some CDMA operators.
+ *
+ * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset).
+ * @return true on success; false on any failure.
+ * @hide
+ */
+ public boolean nvResetConfig(int resetType) {
+ try {
+ return getITelephony().nvResetConfig(resetType);
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "nvResetConfig RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "nvResetConfig NPE", ex);
+ }
+ return false;
+ }
+
+ /**
+ * Change the radio to the specified mode.
+ * Used for device configuration by some operators.
+ *
+ * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode,
+ * or 3 to reset the radio.
+ * @return true on success; false on any failure.
+ * @hide
+ */
+ public boolean setRadioMode(int radioMode) {
+ try {
+ return getITelephony().setRadioMode(radioMode);
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setRadioMode RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "setRadioMode NPE", ex);
+ }
+ return false;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d9e9d56..370e27a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -365,4 +365,51 @@
*/
String iccTransmitApduLogicalChannel(int channel, int cla, int instruction,
int p1, int p2, int p3, String data);
+
+ /**
+ * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
+ * Used for device configuration by some CDMA operators.
+ *
+ * @param itemID the ID of the item to read.
+ * @return the NV item as a String, or null on any failure.
+ */
+ String nvReadItem(int itemID);
+
+ /**
+ * Write one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
+ * Used for device configuration by some CDMA operators.
+ *
+ * @param itemID the ID of the item to read.
+ * @param itemValue the value to write, as a String.
+ * @return true on success; false on any failure.
+ */
+ boolean nvWriteItem(int itemID, String itemValue);
+
+ /**
+ * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
+ * Used for device configuration by some CDMA operators.
+ *
+ * @param preferredRoamingList byte array containing the new PRL.
+ * @return true on success; false on any failure.
+ */
+ boolean nvWriteCdmaPrl(in byte[] preferredRoamingList);
+
+ /**
+ * Perform the specified type of NV config reset.
+ * Used for device configuration by some CDMA operators.
+ *
+ * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset).
+ * @return true on success; false on any failure.
+ */
+ boolean nvResetConfig(int resetType);
+
+ /**
+ * Change the radio to the specified mode.
+ * Used for device configuration by some operators.
+ *
+ * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode,
+ * or 3 to reset the radio.
+ * @return true on success; false on any failure.
+ */
+ boolean setRadioMode(int radioMode);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 4163255..fc6c997 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -63,11 +63,11 @@
public static final int LTE_ON_CDMA_FALSE = RILConstants.LTE_ON_CDMA_FALSE;
public static final int LTE_ON_CDMA_TRUE = RILConstants.LTE_ON_CDMA_TRUE;
- // Number presentation type for caller id display (From internal/Conneciton.java)
- public static int PRESENTATION_ALLOWED = 1; // normal
- public static int PRESENTATION_RESTRICTED = 2; // block by user
- public static int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network
- public static int PRESENTATION_PAYPHONE = 4; // show pay phone info
+ // Number presentation type for caller id display (From internal/Connection.java)
+ public static final int PRESENTATION_ALLOWED = 1; // normal
+ public static final int PRESENTATION_RESTRICTED = 2; // block by user
+ public static final int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network
+ public static final int PRESENTATION_PAYPHONE = 4; // show pay phone info
public static final String PHONE_NAME_KEY = "phoneName";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 8e445d9..6015df0 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -72,7 +72,7 @@
AVAILABLE Application Settings menu*/
int NETWORK_MODE_LTE_CDMA_EVDO = 8; /* LTE, CDMA and EvDo */
int NETWORK_MODE_LTE_GSM_WCDMA = 9; /* LTE, GSM/WCDMA */
- int NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
+ int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
int NETWORK_MODE_LTE_ONLY = 11; /* LTE Only mode. */
int NETWORK_MODE_LTE_WCDMA = 12; /* LTE/WCDMA */
int PREFERRED_NETWORK_MODE = NETWORK_MODE_WCDMA_PREF;
@@ -114,6 +114,10 @@
int DEACTIVATE_REASON_RADIO_OFF = 1;
int DEACTIVATE_REASON_PDP_RESET = 2;
+ /* NV config radio reset types. */
+ int NV_CONFIG_RESET_FACTORY = 1;
+ int NV_CONFIG_RESET_NV_ONLY = 2;
+
/*
cat include/telephony/ril.h | \
egrep '^#define' | \
@@ -271,6 +275,12 @@
int RIL_REQUEST_SIM_OPEN_CHANNEL = 115;
int RIL_REQUEST_SIM_CLOSE_CHANNEL = 116;
int RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL = 117;
+ int RIL_REQUEST_NV_READ_ITEM = 118;
+ int RIL_REQUEST_NV_WRITE_ITEM = 119;
+ int RIL_REQUEST_NV_WRITE_CDMA_PRL = 120;
+ int RIL_REQUEST_NV_RESET_CONFIG = 121;
+ int RIL_REQUEST_SET_RADIO_MODE = 122;
+
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index a7baf1c..9ad2d42 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -125,16 +125,14 @@
* Broadcast Action: The data connection state has changed for any one of the
* phone's mobile data connections (eg, default, MMS or GPS specific connection).
* The intent will have the following extra values:</p>
- * <ul>
- * <li><em>phoneName</em> - A string version of the phone name.</li>
- * <li><em>state</em> - One of <code>"CONNECTED"</code>
- * <code>"CONNECTING"</code> or <code>"DISCONNNECTED"</code></li>
- * <li><em>apn</em> - A string that is the APN associated with this
- * connection.</li>
- * <li><em>apnType</em> - A string array of APN types associated with
- * this connection. The APN type <code>"*"</code> is a special
- * type that means this APN services all types.</li>
- * </ul>
+ * <dl>
+ * <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+ * <dt>state</dt><dd>One of {@code CONNECTED}, {@code CONNECTING},
+ * or {@code DISCONNECTED}.</dd>
+ * <dt>apn</dt><dd>A string that is the APN associated with this connection.</dd>
+ * <dt>apnType</dt><dd>A string array of APN types associated with this connection.
+ * The APN type {@code *} is a special type that means this APN services all types.</dd>
+ * </dl>
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
@@ -149,16 +147,14 @@
* Broadcast Action: Occurs when a data connection connects to a provisioning apn
* and is broadcast by the low level data connection code.
* The intent will have the following extra values:</p>
- * <ul>
- * <li><em>apn</em> - A string that is the APN associated with this
- * connection.</li>
- * <li><em>apnType</em> - A string array of APN types associated with
- * this connection. The APN type <code>"*"</code> is a special
- * type that means this APN services all types.</li>
- * <li><em>linkProperties</em> - The <code>LinkProperties</code> for this APN</li>
- * <li><em>linkCapabilities</em> - The <code>linkCapabilities</code> for this APN</li>
- * <li><em>iface</em> - A string that is the name of the interface</li>
- * </ul>
+ * <dl>
+ * <dt>apn</dt><dd>A string that is the APN associated with this connection.</dd>
+ * <dt>apnType</dt><dd>A string array of APN types associated with this connection.
+ * The APN type {@code *} is a special type that means this APN services all types.</dd>
+ * <dt>linkProperties</dt><dd>{@code LinkProperties} for this APN.</dd>
+ * <dt>linkCapabilities</dt><dd>The {@code LinkCapabilities} for this APN.</dd>
+ * <dt>iface</dt><dd>A string that is the name of the interface.</dd>
+ * </dl>
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
@@ -172,12 +168,11 @@
/**
* Broadcast Action: An attempt to establish a data connection has failed.
* The intent will have the following extra values:</p>
- * <ul>
- * <li><em>phoneName</em> &mdash A string version of the phone name.</li>
- * <li><em>state</em> — One of <code>"CONNECTED"</code>
- * <code>"CONNECTING"</code> or <code>"DISCONNNECTED"</code></li>
- * <li><em>reason</em> — A string indicating the reason for the failure, if available</li>
- * </ul>
+ * <dl>
+ * <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+ * <dt>state</dt><dd>One of {@code CONNECTED}, {@code CONNECTING}, or {code DISCONNECTED}.</dd>
+ * <dt>reason</dt><dd>A string indicating the reason for the failure, if available.</dd>
+ * </dl>
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
@@ -192,16 +187,23 @@
/**
* Broadcast Action: The sim card state has changed.
* The intent will have the following extra values:</p>
- * <ul>
- * <li><em>phoneName</em> - A string version of the phone name.</li>
- * <li><em>ss</em> - The sim state. One of
- * <code>"ABSENT"</code> <code>"LOCKED"</code>
- * <code>"READY"</code> <code>"ISMI"</code> <code>"LOADED"</code> </li>
- * <li><em>reason</em> - The reason while ss is LOCKED, otherwise is null
- * <code>"PIN"</code> locked on PIN1
- * <code>"PUK"</code> locked on PUK1
- * <code>"NETWORK"</code> locked on Network Personalization </li>
- * </ul>
+ * <dl>
+ * <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+ * <dt>ss</dt><dd>The sim state. One of:
+ * <dl>
+ * <dt>{@code ABSENT}</dt><dd>SIM card not found</dd>
+ * <dt>{@code LOCKED}</dt><dd>SIM card locked (see {@code reason})</dd>
+ * <dt>{@code READY}</dt><dd>SIM card ready</dd>
+ * <dt>{@code IMSI}</dt><dd>FIXME: what is this state?</dd>
+ * <dt>{@code LOADED}</dt><dd>SIM card data loaded</dd>
+ * </dl></dd>
+ * <dt>reason</dt><dd>The reason why ss is {@code LOCKED}; null otherwise.</dd>
+ * <dl>
+ * <dt>{@code PIN}</dt><dd>locked on PIN1</dd>
+ * <dt>{@code PUK}</dt><dd>locked on PUK1</dd>
+ * <dt>{@code NETWORK}</dt><dd>locked on network personalization</dd>
+ * </dl>
+ * </dl>
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
@@ -272,31 +274,30 @@
/**
* A <em>prefix</em> for the MCC/MNC filtering used with {@link #ACTION_CARRIER_SETUP}.
* The MCC/MNC will be concatenated (zero-padded to 3 digits each) to create a final
- * string of the form:
- * <br />
- * <code>android.intent.category.MCCMNC_310260</code>
+ * string of the form: {@code android.intent.category.MCCMNC_310260}
*/
public static final String CATEGORY_MCCMNC_PREFIX = "android.intent.category.MCCMNC_";
/**
* Broadcast Action: A "secret code" has been entered in the dialer. Secret codes are
- * of the form *#*#<code>#*#*. The intent will have the data URI:</p>
+ * of the form {@code *#*#<code>#*#*}. The intent will have the data URI:
*
- * <p><code>android_secret_code://<code></code></p>
+ * {@code android_secret_code://<code>}
*/
- public static final String SECRET_CODE_ACTION =
- "android.provider.Telephony.SECRET_CODE";
+ public static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
/**
* Broadcast Action: The Service Provider string(s) have been updated. Activities or
* services that use these strings should update their display.
* The intent will have the following extra values:</p>
- * <ul>
- * <li><em>showPlmn</em> - Boolean that indicates whether the PLMN should be shown.</li>
- * <li><em>plmn</em> - The operator name of the registered network, as a string.</li>
- * <li><em>showSpn</em> - Boolean that indicates whether the SPN should be shown.</li>
- * <li><em>spn</em> - The service provider name, as a string.</li>
- * </ul>
+ *
+ * <dl>
+ * <dt>showPlmn</dt><dd>Boolean that indicates whether the PLMN should be shown.</dd>
+ * <dt>plmn</dt><dd>The operator name of the registered network, as a string.</dd>
+ * <dt>showSpn</dt><dd>Boolean that indicates whether the SPN should be shown.</dd>
+ * <dt>spn</dt><dd>The service provider name, as a string.</dd>
+ * </dl>
+ *
* Note that <em>showPlmn</em> may indicate that <em>plmn</em> should be displayed, even
* though the value for <em>plmn</em> is null. This can happen, for example, if the phone
* has not registered to a network yet. In this case the receiver may substitute an
@@ -305,8 +306,7 @@
* It is recommended to display <em>plmn</em> before / above <em>spn</em> if
* both are displayed.
*
- * <p>Note this is a protected intent that can only be sent
- * by the system.
+ * <p>Note: this is a protected intent that can only be sent by the system.
*/
public static final String SPN_STRINGS_UPDATED_ACTION =
"android.provider.Telephony.SPN_STRINGS_UPDATED";
diff --git a/tests/IdleServiceTest/Android.mk b/tests/IdleServiceTest/Android.mk
new file mode 100644
index 0000000..a7879c5
--- /dev/null
+++ b/tests/IdleServiceTest/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := IdleServiceTest
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
diff --git a/tests/IdleServiceTest/AndroidManifest.xml b/tests/IdleServiceTest/AndroidManifest.xml
new file mode 100644
index 0000000..16d2324
--- /dev/null
+++ b/tests/IdleServiceTest/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.idleservicetest">
+
+ <application>
+ <service android:name="TestService"
+ android:exported="true"
+ android:enabled="true"
+ android:permission="android.permission.BIND_IDLE_SERVICE" >
+ <intent-filter>
+ <action android:name="android.service.idle.IdleService" />
+ </intent-filter>
+ </service>
+
+ <service android:name="CrashingTestService"
+ android:exported="true"
+ android:enabled="true"
+ android:permission="android.permission.BIND_IDLE_SERVICE" >
+ <intent-filter>
+ <action android:name="android.service.idle.IdleService" />
+ </intent-filter>
+ </service>
+
+ <service android:name="TimeoutTestService"
+ android:exported="true"
+ android:enabled="true"
+ android:permission="android.permission.BIND_IDLE_SERVICE" >
+ <intent-filter>
+ <action android:name="android.service.idle.IdleService" />
+ </intent-filter>
+ </service>
+
+ <!-- UnpermissionedTestService should never run because it does
+ not require the necessary permission in its <service> block -->
+ <service android:name="UnpermissionedTestService"
+ android:exported="true"
+ android:enabled="true" >
+ <intent-filter>
+ <action android:name="android.service.idle.IdleService" />
+ </intent-filter>
+ </service>
+
+ </application>
+</manifest>
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
new file mode 100644
index 0000000..022ebcf
--- /dev/null
+++ b/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
@@ -0,0 +1,52 @@
+/*
+ * 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.idleservicetest;
+
+import android.app.maintenance.IdleService;
+import android.os.Handler;
+import android.util.Log;
+
+public class CrashingTestService extends IdleService {
+ static final String TAG = "CrashingTestService";
+
+ String mNull = null;
+
+ @Override
+ public boolean onIdleStart() {
+ Log.i(TAG, "Idle maintenance: onIdleStart()");
+
+ Handler h = new Handler();
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ Log.i(TAG, "Explicitly crashing");
+ if (mNull.equals("")) {
+ Log.i(TAG, "won't happen");
+ }
+ }
+ };
+ Log.i(TAG, "Posting explicit crash in 15 seconds");
+ h.postDelayed(r, 15 * 1000);
+ return true;
+ }
+
+ @Override
+ public void onIdleStop() {
+ Log.i(TAG, "Idle maintenance: onIdleStop()");
+ }
+
+}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
new file mode 100644
index 0000000..7e9805f
--- /dev/null
+++ b/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
@@ -0,0 +1,48 @@
+/*
+ * 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.idleservicetest;
+
+import android.app.maintenance.IdleService;
+import android.os.Handler;
+import android.util.Log;
+
+public class TestService extends IdleService {
+ static final String TAG = "TestService";
+
+ @Override
+ public boolean onIdleStart() {
+ Log.i(TAG, "Idle maintenance: onIdleStart()");
+
+ Handler h = new Handler();
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ Log.i(TAG, "Explicitly finishing idle");
+ finishIdle();
+ }
+ };
+ Log.i(TAG, "Posting explicit finish in 15 seconds");
+ h.postDelayed(r, 15 * 1000);
+ return true;
+ }
+
+ @Override
+ public void onIdleStop() {
+ Log.i(TAG, "Idle maintenance: onIdleStop()");
+ }
+
+}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
new file mode 100644
index 0000000..b2ba21b
--- /dev/null
+++ b/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
@@ -0,0 +1,36 @@
+/*
+ * 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.idleservicetest;
+
+import android.app.maintenance.IdleService;
+import android.util.Log;
+
+public class TimeoutTestService extends IdleService {
+ private static final String TAG = "TimeoutTestService";
+
+ @Override
+ public boolean onIdleStart() {
+ Log.i(TAG, "onIdleStart() but anticipating time-slice timeout");
+ return true;
+ }
+
+ @Override
+ public void onIdleStop() {
+ Log.i(TAG, "onIdleStop() so we're done");
+ }
+
+}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
new file mode 100644
index 0000000..b9fe32b
--- /dev/null
+++ b/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.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.idleservicetest;
+
+import android.app.maintenance.IdleService;
+import android.util.Log;
+
+// Should never be invoked because its manifest declaration does not
+// require the necessary permission.
+public class UnpermissionedTestService extends IdleService {
+ private static final String TAG = "UnpermissionedTestService";
+
+ @Override
+ public boolean onIdleStart() {
+ Log.e(TAG, "onIdleStart() for this service should never be called!");
+ return false;
+ }
+
+ @Override
+ public void onIdleStop() {
+ Log.e(TAG, "onIdleStop() for this service should never be called!");
+ }
+
+}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index e412c27..6a3c506 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1631,9 +1631,18 @@
// =========================================================================
// =========================================================================
-status_t AaptGroup::addFile(const sp<AaptFile>& file)
+status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplicate)
{
- if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
+ ssize_t index = mFiles.indexOfKey(file->getGroupEntry());
+ if (index >= 0 && overwriteDuplicate) {
+ fprintf(stderr, "warning: overwriting '%s' with '%s'\n",
+ mFiles[index]->getSourceFile().string(),
+ file->getSourceFile().string());
+ removeFile(index);
+ index = -1;
+ }
+
+ if (index < 0) {
file->mPath = mPath;
mFiles.add(file->getGroupEntry(), file);
return NO_ERROR;
@@ -1739,7 +1748,8 @@
mDirs.removeItem(name);
}
-status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
+status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file,
+ const bool overwrite)
{
sp<AaptGroup> group;
if (mFiles.indexOfKey(leafName) >= 0) {
@@ -1749,12 +1759,12 @@
mFiles.add(leafName, group);
}
- return group->addFile(file);
+ return group->addFile(file, overwrite);
}
ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
const AaptGroupEntry& kind, const String8& resType,
- sp<FilePathStore>& fullResPaths)
+ sp<FilePathStore>& fullResPaths, const bool overwrite)
{
Vector<String8> fileNames;
{
@@ -1813,7 +1823,7 @@
notAdded = true;
}
ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
- resType, fullResPaths);
+ resType, fullResPaths, overwrite);
if (res < NO_ERROR) {
return res;
}
@@ -1823,7 +1833,7 @@
count += res;
} else if (type == kFileTypeRegular) {
sp<AaptFile> file = new AaptFile(pathName, kind, resType);
- status_t err = addLeafFile(fileNames[i], file);
+ status_t err = addLeafFile(fileNames[i], file, overwrite);
if (err != NO_ERROR) {
return err;
}
@@ -2089,24 +2099,24 @@
/*
* If a directory of custom assets was supplied, slurp 'em up.
*/
- if (bundle->getAssetSourceDir()) {
- const char* assetDir = bundle->getAssetSourceDir();
-
- FileType type = getFileType(assetDir);
+ const Vector<const char*>& assetDirs = bundle->getAssetSourceDirs();
+ const int AN = assetDirs.size();
+ for (int i = 0; i < AN; i++) {
+ FileType type = getFileType(assetDirs[i]);
if (type == kFileTypeNonexistent) {
- fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
+ fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDirs[i]);
return UNKNOWN_ERROR;
}
if (type != kFileTypeDirectory) {
- fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
+ fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDirs[i]);
return UNKNOWN_ERROR;
}
- String8 assetRoot(assetDir);
+ String8 assetRoot(assetDirs[i]);
sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
AaptGroupEntry group;
count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
- String8(), mFullAssetPaths);
+ String8(), mFullAssetPaths, true);
if (count < 0) {
totalCount = count;
goto bail;
@@ -2116,9 +2126,10 @@
}
totalCount += count;
- if (bundle->getVerbose())
+ if (bundle->getVerbose()) {
printf("Found %d custom asset file%s in %s\n",
- count, (count==1) ? "" : "s", assetDir);
+ count, (count==1) ? "" : "s", assetDirs[i]);
+ }
}
/*
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 5cfa913..9cc9007 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -235,7 +235,7 @@
const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& getFiles() const
{ return mFiles; }
- status_t addFile(const sp<AaptFile>& file);
+ status_t addFile(const sp<AaptFile>& file, const bool overwriteDuplicate=false);
void removeFile(size_t index);
void print(const String8& prefix) const;
@@ -301,12 +301,14 @@
status_t addDir(const String8& name, const sp<AaptDir>& dir);
sp<AaptDir> makeDir(const String8& name);
status_t addLeafFile(const String8& leafName,
- const sp<AaptFile>& file);
+ const sp<AaptFile>& file,
+ const bool overwrite=false);
virtual ssize_t slurpFullTree(Bundle* bundle,
const String8& srcDir,
const AaptGroupEntry& kind,
const String8& resType,
- sp<FilePathStore>& fullResPaths);
+ sp<FilePathStore>& fullResPaths,
+ const bool overwrite=false);
String8 mLeaf;
String8 mPath;
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 52d9266..cbeaae8 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -55,7 +55,6 @@
mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL),
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
mAutoAddOverlay(false), mGenDependencies(false),
- mAssetSourceDir(NULL),
mCrunchedOutputDir(NULL), mProguardFile(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
@@ -128,8 +127,8 @@
/*
* Input options.
*/
- const char* getAssetSourceDir() const { return mAssetSourceDir; }
- void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
+ const android::Vector<const char*>& getAssetSourceDirs() const { return mAssetSourceDirs; }
+ void addAssetSourceDir(const char* dir) { mAssetSourceDirs.insertAt(dir,0); }
const char* getCrunchedOutputDir() const { return mCrunchedOutputDir; }
void setCrunchedOutputDir(const char* dir) { mCrunchedOutputDir = dir; }
const char* getProguardFile() const { return mProguardFile; }
@@ -266,7 +265,6 @@
const char* mInstrumentationPackageNameOverride;
bool mAutoAddOverlay;
bool mGenDependencies;
- const char* mAssetSourceDir;
const char* mCrunchedOutputDir;
const char* mProguardFile;
const char* mAndroidManifestFile;
@@ -278,6 +276,7 @@
android::Vector<const char*> mPackageIncludes;
android::Vector<const char*> mJarFiles;
android::Vector<const char*> mNoCompressExtensions;
+ android::Vector<const char*> mAssetSourceDirs;
android::Vector<const char*> mResourceSourceDirs;
const char* mManifestMinSdkVersion;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index c527388..48e3125 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -2034,7 +2034,7 @@
N = bundle->getFileSpecCount();
if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
- && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) {
+ && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
fprintf(stderr, "ERROR: no input files\n");
goto bail;
}
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 51a1248..1ed4630 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -349,7 +349,7 @@
goto bail;
}
convertPath(argv[0]);
- bundle.setAssetSourceDir(argv[0]);
+ bundle.addAssetSourceDir(argv[0]);
break;
case 'G':
argc--;
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 8794452..c3e06d2 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -51,6 +51,7 @@
private BridgeContext mContext;
private IProjectCallback mProjectCallback;
private boolean[] mPlatformResourceFlag = new boolean[1];
+ private TypedValue mTmpValue = new TypedValue();
/**
* Simpler wrapper around FileInputStream. This is used when the input stream represent