diff options
Diffstat (limited to 'core')
165 files changed, 3973 insertions, 1795 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 8ab344e..89a9692 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -788,8 +788,8 @@ public class Activity extends ContextThemeWrapper final Handler mHandler = new Handler(); ActivityTransitionState mActivityTransitionState = new ActivityTransitionState(); - SharedElementListener mEnterTransitionListener = SharedElementListener.NULL_LISTENER; - SharedElementListener mExitTransitionListener = SharedElementListener.NULL_LISTENER; + SharedElementCallback mEnterTransitionListener = SharedElementCallback.NULL_CALLBACK; + SharedElementCallback mExitTransitionListener = SharedElementCallback.NULL_CALLBACK; /** Return the intent that started this activity. */ public Intent getIntent() { @@ -955,7 +955,7 @@ public class Activity extends ContextThemeWrapper * @see #onRestoreInstanceState * @see #onPostCreate */ - protected void onCreate(@Nullable Bundle savedInstanceState, + public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { onCreate(savedInstanceState); } @@ -1040,7 +1040,7 @@ public class Activity extends ContextThemeWrapper * @see #onResume * @see #onSaveInstanceState */ - protected void onRestoreInstanceState(Bundle savedInstanceState, + public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) { if (savedInstanceState != null) { onRestoreInstanceState(savedInstanceState); @@ -1130,7 +1130,7 @@ public class Activity extends ContextThemeWrapper * * @see #onCreate */ - protected void onPostCreate(@Nullable Bundle savedInstanceState, + public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { onPostCreate(savedInstanceState); } @@ -1380,7 +1380,7 @@ public class Activity extends ContextThemeWrapper * @see #onRestoreInstanceState(Bundle, PersistableBundle) * @see #onPause */ - protected void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { + public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { onSaveInstanceState(outState); } @@ -4769,7 +4769,7 @@ public class Activity extends ContextThemeWrapper * @param data An Intent, which can return result data to the caller * (various data can be attached to Intent "extras"). */ - protected void onActivityReenter(int resultCode, Intent data) { + public void onActivityReenter(int resultCode, Intent data) { } /** @@ -5410,6 +5410,7 @@ public class Activity extends ContextThemeWrapper mTranslucentCallback = callback; mChangeCanvasToTranslucent = ActivityManagerNative.getDefault().convertToTranslucent(mToken, options); + WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, false); drawComplete = true; } catch (RemoteException e) { // Make callback return as though it timed out. @@ -5778,33 +5779,33 @@ public class Activity extends ContextThemeWrapper /** * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, - * android.view.View, String)} was used to start an Activity, <var>listener</var> + * android.view.View, String)} was used to start an Activity, <var>callback</var> * will be called to handle shared elements on the <i>launched</i> Activity. This requires * {@link Window#FEATURE_CONTENT_TRANSITIONS}. * - * @param listener Used to manipulate shared element transitions on the launched Activity. + * @param callback Used to manipulate shared element transitions on the launched Activity. */ - public void setEnterSharedElementListener(SharedElementListener listener) { - if (listener == null) { - listener = SharedElementListener.NULL_LISTENER; + public void setEnterSharedElementCallback(SharedElementCallback callback) { + if (callback == null) { + callback = SharedElementCallback.NULL_CALLBACK; } - mEnterTransitionListener = listener; + mEnterTransitionListener = callback; } /** * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, - * android.view.View, String)} was used to start an Activity, <var>listener</var> + * android.view.View, String)} was used to start an Activity, <var>callback</var> * will be called to handle shared elements on the <i>launching</i> Activity. Most * calls will only come when returning from the started Activity. * This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}. * - * @param listener Used to manipulate shared element transitions on the launching Activity. + * @param callback Used to manipulate shared element transitions on the launching Activity. */ - public void setExitSharedElementListener(SharedElementListener listener) { - if (listener == null) { - listener = SharedElementListener.NULL_LISTENER; + public void setExitSharedElementCallback(SharedElementCallback callback) { + if (callback == null) { + callback = SharedElementCallback.NULL_CALLBACK; } - mExitTransitionListener = listener; + mExitTransitionListener = callback; } /** diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index bc54055..3e03893 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -18,12 +18,14 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Point; import android.os.BatteryStats; import android.os.IBinder; import android.os.ParcelFileDescriptor; + import com.android.internal.app.ProcessStats; import com.android.internal.os.TransferPipe; import com.android.internal.util.FastPrintWriter; @@ -2464,7 +2466,11 @@ public class ActivityManager { } } - /** @hide */ + /** + * Gets the userId of the current foreground user. Requires system permissions. + * @hide + */ + @SystemApi public static int getCurrentUser() { UserInfo ui; try { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 38999a8..4f2a3bc 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1938,7 +1938,7 @@ public final class ActivityThread { if (dumpFullInfo) { printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private", "Shared", "Private", "Swapped", "Heap", "Heap", "Heap"); - printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty", + printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "", "Clean", "Clean", "Dirty", "Size", "Alloc", "Free"); printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------", "------", "------", "------", "------", "------", "------"); diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index a09a2e7..9e80a4b 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -197,7 +197,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { final protected ArrayList<View> mSharedElements = new ArrayList<View>(); final protected ArrayList<String> mSharedElementNames = new ArrayList<String>(); final protected ArrayList<View> mTransitioningViews = new ArrayList<View>(); - protected SharedElementListener mListener; + protected SharedElementCallback mListener; protected ResultReceiver mResultReceiver; final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback(); final protected boolean mIsReturning; @@ -208,7 +208,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { public ActivityTransitionCoordinator(Window window, ArrayList<String> allSharedElementNames, - SharedElementListener listener, boolean isReturning) { + SharedElementCallback listener, boolean isReturning) { super(new Handler()); mWindow = window; mListener = listener; @@ -218,7 +218,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { protected void viewsReady(ArrayMap<String, View> sharedElements) { sharedElements.retainAll(mAllSharedElementNames); - mListener.remapSharedElements(mAllSharedElementNames, sharedElements); + mListener.onMapSharedElements(mAllSharedElementNames, sharedElements); mSharedElementNames.addAll(sharedElements.keySet()); mSharedElements.addAll(sharedElements.values()); if (getViewsTransition() != null) { @@ -251,9 +251,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { */ protected void setEpicenter() { View epicenter = null; - if (!mAllSharedElementNames.isEmpty() && !mSharedElementNames.isEmpty() && - mAllSharedElementNames.get(0).equals(mSharedElementNames.get(0))) { - epicenter = mSharedElements.get(0); + if (!mAllSharedElementNames.isEmpty() && !mSharedElementNames.isEmpty()) { + int index = mSharedElementNames.indexOf(mAllSharedElementNames.get(0)); + if (index >= 0) { + epicenter = mSharedElements.get(index); + } } setEpicenter(epicenter); } @@ -458,20 +460,21 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { tempMatrix, tempRect, null); } } - mListener.setSharedElementStart(mSharedElementNames, mSharedElements, snapshots); + mListener.onSharedElementStart(mSharedElementNames, mSharedElements, snapshots); return originalImageState; } protected void notifySharedElementEnd(ArrayList<View> snapshots) { - mListener.setSharedElementEnd(mSharedElementNames, mSharedElements, snapshots); + mListener.onSharedElementEnd(mSharedElementNames, mSharedElements, snapshots); } protected void scheduleSetSharedElementEnd(final ArrayList<View> snapshots) { - getDecor().getViewTreeObserver().addOnPreDrawListener( + final View decorView = getDecor(); + decorView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); notifySharedElementEnd(snapshots); return true; } @@ -526,7 +529,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { Parcelable parcelable = sharedElementBundle.getParcelable(KEY_SNAPSHOT); View snapshot = null; if (parcelable != null) { - snapshot = mListener.createSnapshotView(context, parcelable); + snapshot = mListener.onCreateSnapshotView(context, parcelable); } if (snapshot != null) { setSharedElementState(snapshot, name, state, null, null, decorLoc); @@ -618,7 +621,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ()); sharedElementBundle.putFloat(KEY_ELEVATION, view.getElevation()); - Parcelable bitmap = mListener.captureSharedElementSnapshot(view, tempMatrix, tempBounds); + Parcelable bitmap = mListener.onCaptureSharedElementSnapshot(view, tempMatrix, tempBounds); if (bitmap != null) { sharedElementBundle.putParcelable(KEY_SNAPSHOT, bitmap); } @@ -664,8 +667,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { GhostView.addGhost(view, decor); ViewGroup parent = (ViewGroup) view.getParent(); if (moveWithParent && !isInTransitionGroup(parent, decor)) { - GhostViewListeners listener = - new GhostViewListeners(view, decor); + GhostViewListeners listener = new GhostViewListeners(view, parent, decor); parent.getViewTreeObserver().addOnPreDrawListener(listener); mGhostViewListeners.add(listener); } @@ -723,11 +725,12 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } protected void scheduleGhostVisibilityChange(final int visibility) { - getDecor().getViewTreeObserver() + final View decorView = getDecor(); + decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); setGhostVisibility(visibility); return true; } @@ -769,10 +772,12 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { private static class GhostViewListeners implements ViewTreeObserver.OnPreDrawListener { private View mView; private ViewGroup mDecor; + private View mParent; private Matrix mMatrix = new Matrix(); - public GhostViewListeners(View view, ViewGroup decor) { + public GhostViewListeners(View view, View parent, ViewGroup decor) { mView = view; + mParent = parent; mDecor = decor; } @@ -782,10 +787,9 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { @Override public boolean onPreDraw() { - ViewGroup parent = ((ViewGroup) mView.getParent()); GhostView ghostView = GhostView.getGhost(mView); if (ghostView == null) { - parent.getViewTreeObserver().removeOnPreDrawListener(this); + mParent.getViewTreeObserver().removeOnPreDrawListener(this); } else { GhostView.calculateMatrix(mView, mDecor, mMatrix); ghostView.setMatrix(mMatrix); diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java index 613e248..ad4a22b 100644 --- a/core/java/android/app/ActivityTransitionState.java +++ b/core/java/android/app/ActivityTransitionState.java @@ -151,6 +151,7 @@ class ActivityTransitionState { mEnterActivityOptions = options; mIsEnterTriggered = false; if (mEnterActivityOptions.isReturning()) { + restoreExitedViews(); int result = mEnterActivityOptions.getResultCode(); if (result != 0) { activity.onActivityReenter(result, mEnterActivityOptions.getResultData()); diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index a64e0ed..2c596e5 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -17,6 +17,7 @@ package android.app; import android.annotation.SdkConstant; +import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; import android.os.Build; @@ -385,6 +386,7 @@ public class AlarmManager } /** @hide */ + @SystemApi public void set(int type, long triggerAtMillis, long windowMillis, long intervalMillis, PendingIntent operation, WorkSource workSource) { setImpl(type, triggerAtMillis, windowMillis, intervalMillis, operation, workSource, null); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 66928ca..ba9c9d6 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -220,6 +220,9 @@ public class AppOpsManager { /** Continually monitoring location data with a relatively high power request. */ public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power"; + /** Access to {@link android.app.usage.UsageStatsManager}. */ + public static final String OPSTR_GET_USAGE_STATS + = "android:get_usage_stats"; /** Activate a VPN connection without user intervention. @hide */ @SystemApi public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; @@ -331,7 +334,7 @@ public class AppOpsManager { null, OPSTR_MONITOR_LOCATION, OPSTR_MONITOR_HIGH_POWER_LOCATION, - null, + OPSTR_GET_USAGE_STATS, null, null, null, diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 6843827..e2def31 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1640,7 +1640,10 @@ final class ApplicationPackageManager extends PackageManager { if (itemInfo.showUserIcon != UserHandle.USER_NULL) { return new BitmapDrawable(getUserManager().getUserIcon(itemInfo.showUserIcon)); } - Drawable dr = getDrawable(itemInfo.packageName, itemInfo.icon, appInfo); + Drawable dr = null; + if (itemInfo.packageName != null) { + dr = getDrawable(itemInfo.packageName, itemInfo.icon, appInfo); + } if (dr == null) { dr = itemInfo.loadDefaultIcon(this); } diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 67863a5..8227915 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -23,15 +23,17 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.transition.Transition; -import android.transition.TransitionInflater; import android.transition.TransitionManager; import android.transition.TransitionSet; +import android.transition.TransitionUtils; import android.util.ArrayMap; import android.util.Log; import android.util.LogWriter; import android.util.Pair; +import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -42,8 +44,6 @@ final class BackStackState implements Parcelable { final int[] mOps; final int mTransition; final int mTransitionStyle; - final int mCustomTransition; - final int mSceneRoot; final String mName; final int mIndex; final int mBreadCrumbTitleRes; @@ -96,8 +96,6 @@ final class BackStackState implements Parcelable { mBreadCrumbTitleText = bse.mBreadCrumbTitleText; mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes; mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText; - mCustomTransition = bse.mCustomTransition; - mSceneRoot = bse.mSceneRoot; mSharedElementSourceNames = bse.mSharedElementSourceNames; mSharedElementTargetNames = bse.mSharedElementTargetNames; } @@ -112,8 +110,6 @@ final class BackStackState implements Parcelable { mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mBreadCrumbShortTitleRes = in.readInt(); mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - mCustomTransition = in.readInt(); - mSceneRoot = in.readInt(); mSharedElementSourceNames = in.createStringArrayList(); mSharedElementTargetNames = in.createStringArrayList(); } @@ -164,8 +160,6 @@ final class BackStackState implements Parcelable { bse.mBreadCrumbTitleText = mBreadCrumbTitleText; bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes; bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText; - bse.mCustomTransition = mCustomTransition; - bse.mSceneRoot = mSceneRoot; bse.mSharedElementSourceNames = mSharedElementSourceNames; bse.mSharedElementTargetNames = mSharedElementTargetNames; bse.bumpBackStackNesting(1); @@ -186,8 +180,6 @@ final class BackStackState implements Parcelable { TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0); dest.writeInt(mBreadCrumbShortTitleRes); TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0); - dest.writeInt(mCustomTransition); - dest.writeInt(mSceneRoot); dest.writeStringList(mSharedElementSourceNames); dest.writeStringList(mSharedElementTargetNames); } @@ -254,8 +246,6 @@ final class BackStackRecord extends FragmentTransaction implements int mBreadCrumbShortTitleRes; CharSequence mBreadCrumbShortTitleText; - int mCustomTransition; - int mSceneRoot; ArrayList<String> mSharedElementSourceNames; ArrayList<String> mSharedElementTargetNames; @@ -573,13 +563,6 @@ final class BackStackRecord extends FragmentTransaction implements } @Override - public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) { - mSceneRoot = sceneRootId; - mCustomTransition = transitionId; - return this; - } - - @Override public FragmentTransaction addSharedElement(View sharedElement, String name) { String transitionName = sharedElement.getTransitionName(); if (transitionName == null) { @@ -760,8 +743,15 @@ final class BackStackRecord extends FragmentTransaction implements bumpBackStackNesting(1); - TransitionState state = beginTransition(mSharedElementSourceNames, - mSharedElementTargetNames); + SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>(); + SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>(); + + calculateFragments(firstOutFragments, lastInFragments); + + TransitionState state = null; + if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) { + state = beginTransition(firstOutFragments, lastInFragments, false); + } Op op = mHead; while (op != null) { @@ -854,144 +844,608 @@ final class BackStackRecord extends FragmentTransaction implements } if (state != null) { - updateTransitionEndState(state, mSharedElementTargetNames); + updateTransitionEndState(state, firstOutFragments, lastInFragments, false); } } - private TransitionState beginTransition(ArrayList<String> sourceNames, - ArrayList<String> targetNames) { - if (mCustomTransition <= 0 || mSceneRoot <= 0) { - return null; + private static void setFirstOut(SparseArray<Fragment> fragments, Fragment fragment) { + if (fragment != null) { + int containerId = fragment.mContainerId; + if (containerId != 0 && !fragment.isHidden() && fragment.isAdded() && + fragment.getView() != null && fragments.get(containerId) == null) { + fragments.put(containerId, fragment); + } + } + } + + private void setLastIn(SparseArray<Fragment> fragments, Fragment fragment) { + if (fragment != null) { + int containerId = fragment.mContainerId; + if (containerId != 0) { + fragments.put(containerId, fragment); + } + } + } + + /** + * Finds the first removed fragment and last added fragments when going forward. + * If none of the fragments have transitions, then both lists will be empty. + * + * @param firstOutFragments The list of first fragments to be removed, keyed on the + * container ID. This list will be modified by the method. + * @param lastInFragments The list of last fragments to be added, keyed on the + * container ID. This list will be modified by the method. + */ + private void calculateFragments(SparseArray<Fragment> firstOutFragments, + SparseArray<Fragment> lastInFragments) { + Op op = mHead; + while (op != null) { + switch (op.cmd) { + case OP_ADD: + setLastIn(lastInFragments, op.fragment); + break; + case OP_REPLACE: { + Fragment f = op.fragment; + if (mManager.mAdded != null) { + for (int i = 0; i < mManager.mAdded.size(); i++) { + Fragment old = mManager.mAdded.get(i); + if (f == null || old.mContainerId == f.mContainerId) { + if (old == f) { + f = null; + } else { + setFirstOut(firstOutFragments, old); + } + } + } + } + setLastIn(lastInFragments, f); + break; + } + case OP_REMOVE: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_HIDE: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_SHOW: + setLastIn(lastInFragments, op.fragment); + break; + case OP_DETACH: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_ATTACH: + setLastIn(lastInFragments, op.fragment); + break; + } + + op = op.next; + } + + if (!haveTransitions(firstOutFragments, lastInFragments, false)) { + firstOutFragments.clear(); + lastInFragments.clear(); + } + } + + /** + * @return true if custom transitions exist on any fragment in firstOutFragments or + * lastInFragments or false otherwise. + */ + private static boolean haveTransitions(SparseArray<Fragment> firstOutFragments, + SparseArray<Fragment> lastInFragments, boolean isBack) { + for (int i = firstOutFragments.size() - 1; i >= 0; i--) { + Fragment f = firstOutFragments.valueAt(i); + if (isBack) { + if (f.getReturnTransition() != null || + f.getSharedElementReturnTransition() != null) { + return true; + } + } else if (f.getExitTransition() != null) { + return true; + } + } + + for (int i = lastInFragments.size() - 1; i >= 0; i--) { + Fragment f = lastInFragments.valueAt(i); + if (isBack) { + if (f.getReenterTransition() != null) { + return true; + } + } else if (f.getEnterTransition() != null || + f.getSharedElementEnterTransition() != null) { + return true; + } } - View rootView = mManager.mContainer.findViewById(mSceneRoot); - if (!(rootView instanceof ViewGroup)) { - throw new IllegalArgumentException("SceneRoot is not a ViewGroup"); + return false; + } + + /** + * Finds the first removed fragment and last added fragments when popping the back stack. + * If none of the fragments have transitions, then both lists will be empty. + * + * @param firstOutFragments The list of first fragments to be removed, keyed on the + * container ID. This list will be modified by the method. + * @param lastInFragments The list of last fragments to be added, keyed on the + * container ID. This list will be modified by the method. + */ + public void calculateBackFragments(SparseArray<Fragment> firstOutFragments, + SparseArray<Fragment> lastInFragments) { + Op op = mHead; + while (op != null) { + switch (op.cmd) { + case OP_ADD: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_REPLACE: + if (op.removed != null) { + for (int i = op.removed.size() - 1; i >= 0; i--) { + setLastIn(lastInFragments, op.removed.get(i)); + } + } + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_REMOVE: + setLastIn(lastInFragments, op.fragment); + break; + case OP_HIDE: + setLastIn(lastInFragments, op.fragment); + break; + case OP_SHOW: + setFirstOut(firstOutFragments, op.fragment); + break; + case OP_DETACH: + setLastIn(lastInFragments, op.fragment); + break; + case OP_ATTACH: + setFirstOut(firstOutFragments, op.fragment); + break; + } + + op = op.next; } + + if (!haveTransitions(firstOutFragments, lastInFragments, true)) { + firstOutFragments.clear(); + lastInFragments.clear(); + } + } + + /** + * When custom fragment transitions are used, this sets up the state for each transition + * and begins the transition. A different transition is started for each fragment container + * and consists of up to 3 different transitions: the exit transition, a shared element + * transition and an enter transition. + * + * <p>The exit transition operates against the leaf nodes of the first fragment + * with a view that was removed. If no such fragment was removed, then no exit + * transition is executed. The exit transition comes from the outgoing fragment.</p> + * + * <p>The enter transition operates against the last fragment that was added. If + * that fragment does not have a view or no fragment was added, then no enter + * transition is executed. The enter transition comes from the incoming fragment.</p> + * + * <p>The shared element transition operates against all views and comes either + * from the outgoing fragment or the incoming fragment, depending on whether this + * is going forward or popping the back stack. When going forward, the incoming + * fragment's enter shared element transition is used, but when going back, the + * outgoing fragment's return shared element transition is used. Shared element + * transitions only operate if there is both an incoming and outgoing fragment.</p> + * + * @param firstOutFragments The list of first fragments to be removed, keyed on the + * container ID. + * @param lastInFragments The list of last fragments to be added, keyed on the + * container ID. + * @param isBack true if this is popping the back stack or false if this is a + * forward operation. + * @return The TransitionState used to complete the operation of the transition + * in {@link #updateTransitionEndState(android.app.BackStackRecord.TransitionState, + * android.util.SparseArray, android.util.SparseArray, boolean)}. + */ + private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments, + SparseArray<Fragment> lastInFragments, boolean isBack) { TransitionState state = new TransitionState(); - // get Transition scene root and create Transitions - state.sceneRoot = (ViewGroup) rootView; - state.sceneRoot.captureTransitioningViews(state.transitioningViews); - - state.exitTransition = TransitionInflater.from(mManager.mActivity) - .inflateTransition(mCustomTransition); - state.sharedElementTransition = TransitionInflater.from(mManager.mActivity) - .inflateTransition(mCustomTransition); - state.enterTransition = TransitionInflater.from(mManager.mActivity) - .inflateTransition(mCustomTransition); + // Adding a non-existent target view makes sure that the transitions don't target // any views by default. They'll only target the views we tell add. If we don't // add any, then no views will be targeted. - View nonExistentView = new View(mManager.mActivity); - state.enterTransition.addTarget(nonExistentView); - state.exitTransition.addTarget(nonExistentView); - state.sharedElementTransition.addTarget(nonExistentView); - - setSharedElementEpicenter(state.enterTransition, state); - - state.excludingTransition = new TransitionSet() - .addTransition(state.exitTransition) - .addTransition(state.enterTransition); + state.nonExistentView = new View(mManager.mActivity); + + ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>(); + ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>(); + ArrayList<String> tempNames = new ArrayList<String>(); + ArrayList<View> tempViewList = new ArrayList<View>(); + + // Go over all leaving fragments. + for (int i = 0; i < firstOutFragments.size(); i++) { + int containerId = firstOutFragments.keyAt(i); + configureTransitions(containerId, state, isBack, firstOutFragments, + lastInFragments, tempViews1, tempViews2, tempNames, tempViewList); + } - if (sourceNames != null) { - // Map shared elements. - state.sceneRoot.findNamedViews(state.namedViews); - state.namedViews.retainAll(sourceNames); - View epicenterView = state.namedViews.get(sourceNames.get(0)); - if (epicenterView != null) { - // The epicenter is only the first shared element. - setEpicenter(state.exitTransition, epicenterView); - setEpicenter(state.sharedElementTransition, epicenterView); + // Now go over all entering fragments that didn't have a leaving fragment. + for (int i = 0; i < lastInFragments.size(); i++) { + int containerId = lastInFragments.keyAt(i); + if (firstOutFragments.get(containerId) == null) { + configureTransitions(containerId, state, isBack, firstOutFragments, + lastInFragments, tempViews1, tempViews2, tempNames, tempViewList); } - state.transitioningViews.removeAll(state.namedViews.values()); - state.excludingTransition.addTransition(state.sharedElementTransition); - addTransitioningViews(state.sharedElementTransition, state.namedViews.values()); } - // Adds the (maybe) exiting views, not including the shared element. - // If some stay, that's ok. - addTransitioningViews(state.exitTransition, state.transitioningViews); + if (state.overallTransitions.size() == 0) { + state = null; + } + return state; + } - // Prepare for shared element name mapping. This could be chained in the case - // of popping several back stack states. - state.excludingTransition.setNameOverrides(new ArrayMap<String, String>()); - setNameOverrides(state, sourceNames, targetNames); + private static Transition getEnterTransition(Fragment inFragment, boolean isBack) { + if (inFragment == null) { + return null; + } + return isBack ? inFragment.getReenterTransition() : inFragment.getEnterTransition(); + } - // Don't include any subtree in the views that are hidden when capturing the - // view hierarchy transitions. They should be as if not there. - excludeHiddenFragments(state, true); + private static Transition getExitTransition(Fragment outFragment, boolean isBack) { + if (outFragment == null) { + return null; + } + return isBack ? outFragment.getReturnTransition() : outFragment.getExitTransition(); + } - TransitionManager.beginDelayedTransition(state.sceneRoot, state.excludingTransition); - return state; + private static Transition getSharedElementTransition(Fragment inFragment, Fragment outFragment, + boolean isBack) { + if (inFragment == null || outFragment == null) { + return null; + } + return isBack ? outFragment.getSharedElementReturnTransition() : + inFragment.getSharedElementEnterTransition(); } - private void updateTransitionEndState(TransitionState state, ArrayList<String> names) { - // Find all views that are entering. - ArrayList<View> enteringViews = new ArrayList<View>(); - state.sceneRoot.captureTransitioningViews(enteringViews); - enteringViews.removeAll(state.transitioningViews); - - if (names != null) { - // find all shared elements. - state.namedViews.clear(); - state.sceneRoot.findNamedViews(state.namedViews); - state.namedViews.retainAll(names); - if (!state.namedViews.isEmpty()) { - enteringViews.removeAll(state.namedViews.values()); - addTransitioningViews(state.sharedElementTransition, state.namedViews.values()); - // now we know the epicenter of the entering transition. - state.mEnteringEpicenterView = state.namedViews.get(names.get(0)); + private static Transition captureExitingViews(Transition exitTransition, Fragment outFragment, + ArrayList<View> viewList) { + if (exitTransition != null) { + View root = outFragment.getView(); + viewList.clear(); + root.captureTransitioningViews(viewList); + if (viewList.isEmpty()) { + exitTransition = null; + } else { + addTransitioningViews(exitTransition, viewList); + } + } + return exitTransition; + } + + private ArrayMap<String, View> remapSharedElements(TransitionState state, Fragment outFragment, + ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) { + if (mSharedElementSourceNames != null) { + outFragment.getView().findNamedViews(namedViews); + if (isBack) { + namedViews.retainAll(mSharedElementTargetNames); + } else { + namedViews = remapNames(mSharedElementSourceNames, mSharedElementTargetNames, + namedViews, tempViews2); } } - // Add all entering views to the enter transition. - addTransitioningViews(state.enterTransition, enteringViews); + if (isBack) { + outFragment.mEnterTransitionCallback.onMapSharedElements( + mSharedElementTargetNames, namedViews); + setBackNameOverrides(state, namedViews, false); + } else { + outFragment.mExitTransitionCallback.onMapSharedElements( + mSharedElementTargetNames, namedViews); + setNameOverrides(state, namedViews, false); + } - // Don't allow capturing state for the newly-hidden fragments. - excludeHiddenFragments(state, false); + return namedViews; + } - // Allow capturing state for the newly-shown fragments - includeVisibleFragments(state.excludingTransition); + /** + * Prepares the enter transition by adding a non-existent view to the transition's target list + * and setting it epicenter callback. By adding a non-existent view to the target list, + * we can prevent any view from being targeted at the beginning of the transition. + * We will add to the views before the end state of the transition is captured so that the + * views will appear. At the start of the transition, we clear the list of targets so that + * we can restore the state of the transition and use it again. + */ + private void prepareEnterTransition(TransitionState state, final Transition enterTransition, + final View container, final Fragment inFragment) { + if (enterTransition != null) { + final ArrayList<View> enteringViews = new ArrayList<View>(); + final View nonExistentView = state.nonExistentView; + enterTransition.addTarget(state.nonExistentView); + enterTransition.addListener(new Transition.TransitionListenerAdapter() { + @Override + public void onTransitionStart(Transition transition) { + transition.removeListener(this); + transition.removeTarget(nonExistentView); + int numViews = enteringViews.size(); + for (int i = 0; i < numViews; i++) { + transition.removeTarget(enteringViews.get(i)); + } + } + }); + container.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + container.getViewTreeObserver().removeOnPreDrawListener(this); + View view = inFragment.getView(); + if (view != null) { + view.captureTransitioningViews(enteringViews); + addTransitioningViews(enterTransition, enteringViews); + } + return true; + } + }); + setSharedElementEpicenter(enterTransition, state); + } } - private void addTransitioningViews(Transition transition, Collection<View> views) { - if (views.isEmpty()) { - // Add a view so that we can modify the valid views at the end of the - // fragment transaction. - transition.addTarget(new View(mManager.mActivity)); + private static Transition mergeTransitions(Transition enterTransition, + Transition exitTransition, Transition sharedElementTransition, Fragment inFragment, + boolean isBack) { + boolean overlap = true; + if (enterTransition != null && exitTransition != null) { + overlap = isBack ? inFragment.getAllowReturnTransitionOverlap() : + inFragment.getAllowEnterTransitionOverlap(); + } + + Transition transition; + if (overlap) { + transition = TransitionUtils.mergeTransitions(enterTransition, exitTransition, + sharedElementTransition); } else { - for (View view : views) { - transition.addTarget(view); + TransitionSet staggered = new TransitionSet() + .addTransition(exitTransition) + .addTransition(enterTransition) + .setOrdering(TransitionSet.ORDERING_SEQUENTIAL); + transition = TransitionUtils.mergeTransitions(staggered, sharedElementTransition); + } + return transition; + } + + /** + * Configures custom transitions for a specific fragment container. + * + * @param containerId The container ID of the fragments to configure the transition for. + * @param state The Transition State to be shared with {@link #updateTransitionEndState( + * android.app.BackStackRecord.TransitionState, android.util.SparseArray, + * android.util.SparseArray, boolean)} later. + * @param firstOutFragments The list of first fragments to be removed, keyed on the + * container ID. + * @param lastInFragments The list of last fragments to be added, keyed on the + * container ID. + * @param isBack true if this is popping the back stack or false if this is a + * forward operation. + * @param tempViews1 A temporary mapping of names to Views, used to avoid allocation + * inside a loop. + * @param tempViews2 A temporary mapping of names to Views, used to avoid allocation + * inside a loop. + * @param tempNames A temporary list of Strings, used to avoid allocation inside a loop. + * @param tempViewList A temporary list of Views, used to avoid allocation inside a loop. + */ + private void configureTransitions(int containerId, TransitionState state, boolean isBack, + SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments, + ArrayMap<String, View> tempViews1, ArrayMap<String, View> tempViews2, + ArrayList<String> tempNames, ArrayList<View> tempViewList) { + ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId); + if (sceneRoot != null) { + Fragment inFragment = lastInFragments.get(containerId); + Fragment outFragment = firstOutFragments.get(containerId); + + Transition enterTransition = getEnterTransition(inFragment, isBack); + Transition sharedElementTransition = getSharedElementTransition(inFragment, outFragment, + isBack); + Transition exitTransition = getExitTransition(outFragment, isBack); + exitTransition = captureExitingViews(exitTransition, outFragment, tempViewList); + + ArrayMap<String, View> namedViews = tempViews1; + namedViews.clear(); + if (sharedElementTransition != null) { + namedViews = remapSharedElements(state, + outFragment, namedViews, tempViews2, isBack); + } + + // Notify the start of the transition. + SharedElementCallback callback = isBack ? + outFragment.mEnterTransitionCallback : + inFragment.mEnterTransitionCallback; + tempNames.clear(); + tempNames.addAll(namedViews.keySet()); + tempViewList.clear(); + tempViewList.addAll(namedViews.values()); + callback.onSharedElementStart(tempNames, tempViewList, null); + + // Set the epicenter of the exit transition + if (mSharedElementTargetNames != null && exitTransition != null) { + View epicenterView = namedViews.get(mSharedElementTargetNames.get(0)); + if (epicenterView != null) { + setEpicenter(exitTransition, epicenterView); + } + } + + prepareEnterTransition(state, enterTransition, sceneRoot, inFragment); + + Transition transition = mergeTransitions(enterTransition, exitTransition, + sharedElementTransition, inFragment, isBack); + + if (transition != null) { + state.overallTransitions.put(containerId, transition); + transition.setNameOverrides(state.nameOverrides); + // We want to exclude hidden views later, so we need a non-null list in the + // transition now. + transition.excludeTarget(state.nonExistentView, true); + // Now exclude all currently hidden fragments. + excludeHiddenFragments(state, containerId, transition); + cleanupHiddenFragments(transition, state); + TransitionManager.beginDelayedTransition(sceneRoot, transition); } } } - private void excludeHiddenFragments(TransitionState state, boolean forceExclude) { - if (mManager.mAdded != null) { - for (int i = 0; i < mManager.mAdded.size(); i++) { - Fragment fragment = mManager.mAdded.get(i); - if (fragment.mView != null && fragment.mHidden - && (forceExclude || !state.hiddenViews.contains(fragment.mView))) { - state.excludingTransition.excludeTarget(fragment.mView, true); - state.hiddenViews.add(fragment.mView); + /** + * Remaps a name-to-View map, substituting different names for keys. + * + * @param inMap A list of keys found in the map, in the order in toGoInMap + * @param toGoInMap A list of keys to use for the new map, in the order of inMap + * @param namedViews The current mapping + * @param tempMap A temporary mapping that will be filled with the new values. + * @return tempMap after it has been mapped with the new names as keys. + */ + private static ArrayMap<String, View> remapNames(ArrayList<String> inMap, + ArrayList<String> toGoInMap, ArrayMap<String, View> namedViews, + ArrayMap<String, View> tempMap) { + tempMap.clear(); + if (!namedViews.isEmpty()) { + int numKeys = inMap.size(); + for (int i = 0; i < numKeys; i++) { + View view = namedViews.get(inMap.get(i)); + if (view != null) { + tempMap.put(toGoInMap.get(i), view); } } } - if (forceExclude && state.hiddenViews.isEmpty()) { - state.excludingTransition.excludeTarget(new View(mManager.mActivity), true); + return tempMap; + } + + /** + * After making all fragment changes, this updates the custom transitions to take into + * account the entering views and any remapping. + * + * @param state The transition State as returned from {@link #beginTransition( + * android.util.SparseArray, android.util.SparseArray, boolean)}. + * @param outFragments The list of first fragments to be removed, keyed on the + * container ID. + * @param inFragments The list of last fragments to be added, keyed on the + * container ID. + * @param isBack true if this is popping the back stack or false if this is a + * forward operation. + */ + private void updateTransitionEndState(TransitionState state, SparseArray<Fragment> outFragments, + SparseArray<Fragment> inFragments, boolean isBack) { + ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>(); + ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>(); + ArrayList<String> tempNames = new ArrayList<String>(); + ArrayList<View> tempViews = new ArrayList<View>(); + + int numInFragments = inFragments.size(); + for (int i = 0; i < numInFragments; i++) { + Fragment inFragment = inFragments.valueAt(i); + tempViews1.clear(); + ArrayMap<String, View> namedViews = mapEnteringSharedElements(inFragment, tempViews1, + tempViews2, isBack); + // remap shared elements and set the name mapping used in the shared element transition. + if (isBack) { + inFragment.mExitTransitionCallback.onMapSharedElements( + mSharedElementTargetNames, namedViews); + setBackNameOverrides(state, namedViews, true); + } else { + inFragment.mEnterTransitionCallback.onMapSharedElements( + mSharedElementTargetNames, namedViews); + setNameOverrides(state, namedViews, true); + } + + if (mSharedElementTargetNames != null && !namedViews.isEmpty()) { + // now we know the epicenter of the entering transition. + View epicenter = namedViews.get(mSharedElementTargetNames.get(0)); + if (epicenter != null) { + state.enteringEpicenterView = epicenter; + } + } + + int containerId = inFragments.keyAt(i); + SharedElementCallback sharedElementCallback = isBack ? + outFragments.get(containerId).mEnterTransitionCallback : + inFragment.mEnterTransitionCallback; + tempNames.clear(); + tempNames.addAll(namedViews.keySet()); + tempViews.clear(); + tempViews.addAll(namedViews.values()); + sharedElementCallback.onSharedElementEnd(tempNames, tempViews, null); } + + // Don't include any newly-hidden fragments in the transition. + excludeHiddenFragments(state); } - private void includeVisibleFragments(Transition transition) { + private ArrayMap<String, View> mapEnteringSharedElements(Fragment inFragment, + ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) { + View root = inFragment.getView(); + if (root != null) { + if (mSharedElementSourceNames != null) { + root.findNamedViews(namedViews); + if (isBack) { + namedViews = remapNames(mSharedElementSourceNames, + mSharedElementTargetNames, namedViews, tempViews2); + } else { + namedViews.retainAll(mSharedElementTargetNames); + } + } + } + return namedViews; + } + + private static void cleanupHiddenFragments(Transition transition, TransitionState state) { + final ArrayList<View> hiddenViews = state.hiddenFragmentViews; + transition.addListener(new Transition.TransitionListenerAdapter() { + @Override + public void onTransitionStart(Transition transition) { + transition.removeListener(this); + int numViews = hiddenViews.size(); + for (int i = 0; i < numViews; i++) { + transition.excludeTarget(hiddenViews.get(i), false); + } + } + }); + } + + private void excludeHiddenFragments(TransitionState state, int containerId, + Transition transition) { if (mManager.mAdded != null) { for (int i = 0; i < mManager.mAdded.size(); i++) { Fragment fragment = mManager.mAdded.get(i); - if (fragment.mView != null && !fragment.mHidden) { - transition.excludeTarget(fragment.mView, false); + if (fragment.mView != null && fragment.mContainer != null && + fragment.mContainerId == containerId) { + if (fragment.mHidden) { + if (!state.hiddenFragmentViews.contains(fragment.mView)) { + transition.excludeTarget(fragment.mView, true); + state.hiddenFragmentViews.add(fragment.mView); + } + } else { + transition.excludeTarget(fragment.mView, false); + state.hiddenFragmentViews.remove(fragment.mView); + } } } } } + private void excludeHiddenFragments(TransitionState state) { + int numTransitions = state.overallTransitions.size(); + for (int i = 0; i < numTransitions; i++) { + Transition transition = state.overallTransitions.valueAt(i); + int containerId = state.overallTransitions.keyAt(i); + excludeHiddenFragments(state, containerId, transition); + } + } + + private static void addTransitioningViews(Transition transition, final Collection<View> views) { + for (View view : views) { + transition.addTarget(view); + } + + transition.addListener(new Transition.TransitionListenerAdapter() { + @Override + public void onTransitionStart(Transition transition) { + transition.removeListener(this); + for (View view : views) { + transition.removeTarget(view); + } + } + }); + } + private static void setEpicenter(Transition transition, View view) { final Rect epicenter = new Rect(); view.getBoundsOnScreen(epicenter); @@ -1010,16 +1464,17 @@ final class BackStackRecord extends FragmentTransaction implements @Override public Rect onGetEpicenter(Transition transition) { - if (mEpicenter == null && state.mEnteringEpicenterView != null) { + if (mEpicenter == null && state.enteringEpicenterView != null) { mEpicenter = new Rect(); - state.mEnteringEpicenterView.getBoundsOnScreen(mEpicenter); + state.enteringEpicenterView.getBoundsOnScreen(mEpicenter); } return mEpicenter; } }); } - public TransitionState popFromBackStack(boolean doStateMove, TransitionState state) { + public TransitionState popFromBackStack(boolean doStateMove, TransitionState state, + SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) { if (FragmentManagerImpl.DEBUG) { Log.v(TAG, "popFromBackStack: " + this); LogWriter logw = new LogWriter(Log.VERBOSE, TAG); @@ -1029,8 +1484,10 @@ final class BackStackRecord extends FragmentTransaction implements } if (state == null) { - state = beginTransition(mSharedElementTargetNames, mSharedElementSourceNames); - } else { + if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) { + state = beginTransition(firstOutFragments, lastInFragments, true); + } + } else if (!doStateMove) { setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames); } @@ -1110,7 +1567,7 @@ final class BackStackRecord extends FragmentTransaction implements mManager.moveToState(mManager.mCurState, FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true); if (state != null) { - updateTransitionEndState(state, mSharedElementSourceNames); + updateTransitionEndState(state, firstOutFragments, lastInFragments, true); state = null; } } @@ -1122,15 +1579,17 @@ final class BackStackRecord extends FragmentTransaction implements return state; } - private static void setNameOverride(Transition transition, String source, String target) { - ArrayMap<String, String> overrides = transition.getNameOverrides(); - for (int index = 0; index < overrides.size(); index++) { - if (source.equals(overrides.valueAt(index))) { - overrides.setValueAt(index, target); - return; + private static void setNameOverride(ArrayMap<String, String> overrides, + String source, String target) { + if (source != null && target != null && !source.equals(target)) { + for (int index = 0; index < overrides.size(); index++) { + if (source.equals(overrides.valueAt(index))) { + overrides.setValueAt(index, target); + return; + } } + overrides.put(source, target); } - overrides.put(source, target); } private static void setNameOverrides(TransitionState state, ArrayList<String> sourceNames, @@ -1139,7 +1598,36 @@ final class BackStackRecord extends FragmentTransaction implements for (int i = 0; i < sourceNames.size(); i++) { String source = sourceNames.get(i); String target = targetNames.get(i); - setNameOverride(state.excludingTransition, source, target); + setNameOverride(state.nameOverrides, source, target); + } + } + } + + private void setBackNameOverrides(TransitionState state, ArrayMap<String, View> namedViews, + boolean isEnd) { + int count = mSharedElementTargetNames.size(); + for (int i = 0; i < count; i++) { + String source = mSharedElementSourceNames.get(i); + String originalTarget = mSharedElementTargetNames.get(i); + String target = namedViews.get(originalTarget).getTransitionName(); + if (isEnd) { + setNameOverride(state.nameOverrides, source, target); + } else { + setNameOverride(state.nameOverrides, target, source); + } + } + } + + private void setNameOverrides(TransitionState state, ArrayMap<String, View> namedViews, + boolean isEnd) { + int count = namedViews.size(); + for (int i = 0; i < count; i++) { + String source = namedViews.keyAt(i); + String target = namedViews.valueAt(i).getTransitionName(); + if (isEnd) { + setNameOverride(state.nameOverrides, source, target); + } else { + setNameOverride(state.nameOverrides, target, source); } } } @@ -1161,14 +1649,11 @@ final class BackStackRecord extends FragmentTransaction implements } public class TransitionState { - public ArrayList<View> hiddenViews = new ArrayList<View>(); - public ArrayList<View> transitioningViews = new ArrayList<View>(); - public ArrayMap<String, View> namedViews = new ArrayMap<String, View>(); - public Transition exitTransition; - public Transition sharedElementTransition; - public Transition enterTransition; - public TransitionSet excludingTransition; - public ViewGroup sceneRoot; - public View mEnteringEpicenterView; + public SparseArray<Transition> overallTransitions = new SparseArray<Transition>(); + public ArrayMap<String, String> nameOverrides = new ArrayMap<String, String>(); + public ArrayList<View> hiddenFragmentViews = new ArrayList<View>(); + + public View enteringEpicenterView; + public View nonExistentView; } } diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index 47d3fd6..f432c49 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -21,8 +21,6 @@ import android.animation.ObjectAnimator; import android.graphics.Matrix; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.os.ResultReceiver; import android.text.TextUtils; import android.transition.Transition; @@ -71,12 +69,13 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { Bundle resultReceiverBundle = new Bundle(); resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this); mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle); - getDecor().getViewTreeObserver().addOnPreDrawListener( + final View decorView = getDecor(); + decorView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { if (mIsReadyForTransition) { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); } return mIsReadyForTransition; } @@ -170,7 +169,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { private void sendSharedElementDestination() { boolean allReady; - if (allowOverlappingTransitions()) { + if (allowOverlappingTransitions() && getEnterViewsTransition() != null) { allReady = false; } else { allReady = !getDecor().isLayoutRequested(); @@ -189,11 +188,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { moveSharedElementsToOverlay(); mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); } else { - getDecor().getViewTreeObserver() + final View decorView = getDecor(); + decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); if (mResultReceiver != null) { Bundle state = captureSharedElementState(); setSharedElementMatrices(); @@ -209,7 +209,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } } - private static SharedElementListener getListener(Activity activity, boolean isReturning) { + private static SharedElementCallback getListener(Activity activity, boolean isReturning) { return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener; } @@ -294,7 +294,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames); rejectedNames.removeAll(mSharedElementNames); ArrayList<View> rejectedSnapshots = createSnapshots(sharedElementState, rejectedNames); - mListener.handleRejectedSharedElements(rejectedSnapshots); + mListener.onRejectSharedElements(rejectedSnapshots); startRejectedAnimations(rejectedSnapshots); // Now start shared element transition @@ -344,11 +344,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } final Bundle sharedElementState = mSharedElementsBundle; mSharedElementsBundle = null; - getDecor().getViewTreeObserver() + final View decorView = getDecor(); + decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); startTransition(new Runnable() { @Override public void run() { @@ -358,7 +359,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { return false; } }); - getDecor().invalidate(); + decorView.invalidate(); } private void requestLayoutForSharedElements() { @@ -466,6 +467,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { Drawable background = getDecor().getBackground(); if (background != null) { background = background.mutate(); + getWindow().setBackgroundDrawable(background); mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 255); mBackgroundAnimator.setDuration(getFadeDuration()); mBackgroundAnimator.addListener(new AnimatorListenerAdapter() { diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index 3760b96..a59a927 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -79,7 +79,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { mActivity = activity; } - private static SharedElementListener getListener(Activity activity, boolean isReturning) { + private static SharedElementCallback getListener(Activity activity, boolean isReturning) { return isReturning ? activity.mEnterTransitionListener : activity.mExitTransitionListener; } @@ -140,7 +140,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (getDecor() != null) { getDecor().suppressLayout(true); } - if (!mSharedElements.isEmpty() && getSharedElementTransition() != null) { + if (mExitSharedElementBundle != null && !mExitSharedElementBundle.isEmpty() && + !mSharedElements.isEmpty() && getSharedElementTransition() != null) { startTransition(new Runnable() { public void run() { startSharedElementExit(); @@ -164,18 +165,19 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { }); final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames); - getDecor().getViewTreeObserver() + final View decorView = getDecor(); + decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots); return true; } }); setGhostVisibility(View.INVISIBLE); scheduleGhostVisibilityChange(View.INVISIBLE); - mListener.setSharedElementEnd(mSharedElementNames, mSharedElements, sharedElementSnapshots); + mListener.onSharedElementEnd(mSharedElementNames, mSharedElements, sharedElementSnapshots); TransitionManager.beginDelayedTransition(getDecor(), transition); scheduleGhostVisibilityChange(View.VISIBLE); setGhostVisibility(View.VISIBLE); @@ -259,6 +261,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { ViewGroup decor = getDecor(); Drawable background; if (decor != null && (background = decor.getBackground()) != null) { + background = background.mutate(); + getWindow().setBackgroundDrawable(background); mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0); mBackgroundAnimator.addListener(new AnimatorListenerAdapter() { @Override diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 2ff3d57..672ef7b 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -23,10 +23,14 @@ import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.transition.Transition; +import android.transition.TransitionInflater; +import android.transition.TransitionSet; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.AttributeSet; @@ -58,11 +62,11 @@ final class FragmentState implements Parcelable { final boolean mRetainInstance; final boolean mDetached; final Bundle mArguments; - + Bundle mSavedFragmentState; - + Fragment mInstance; - + public FragmentState(Fragment frag) { mClassName = frag.getClass().getName(); mIndex = frag.mIndex; @@ -74,7 +78,7 @@ final class FragmentState implements Parcelable { mDetached = frag.mDetached; mArguments = frag.mArguments; } - + public FragmentState(Parcel in) { mClassName = in.readString(); mIndex = in.readInt(); @@ -87,18 +91,18 @@ final class FragmentState implements Parcelable { mArguments = in.readBundle(); mSavedFragmentState = in.readBundle(); } - + public Fragment instantiate(Activity activity, Fragment parent) { if (mInstance != null) { return mInstance; } - + if (mArguments != null) { mArguments.setClassLoader(activity.getClassLoader()); } - + mInstance = Fragment.instantiate(activity, mClassName, mArguments); - + if (mSavedFragmentState != null) { mSavedFragmentState.setClassLoader(activity.getClassLoader()); mInstance.mSavedFragmentState = mSavedFragmentState; @@ -117,7 +121,7 @@ final class FragmentState implements Parcelable { return mInstance; } - + public int describeContents() { return 0; } @@ -134,13 +138,13 @@ final class FragmentState implements Parcelable { dest.writeBundle(mArguments); dest.writeBundle(mSavedFragmentState); } - + public static final Parcelable.Creator<FragmentState> CREATOR = new Parcelable.Creator<FragmentState>() { public FragmentState createFromParcel(Parcel in) { return new FragmentState(in); } - + public FragmentState[] newArray(int size) { return new FragmentState[size]; } @@ -299,17 +303,17 @@ final class FragmentState implements Parcelable { * how you can determine if a fragment placed in a container is no longer * running in a layout with that container and avoid creating its view hierarchy * in that case.) - * + * * <p>The attributes of the <fragment> tag are used to control the * LayoutParams provided when attaching the fragment's view to the parent * container. They can also be parsed by the fragment in {@link #onInflate} * as parameters. - * + * * <p>The fragment being instantiated must have some kind of unique identifier * so that it can be re-associated with a previous instance if the parent * activity needs to be destroyed and recreated. This can be provided these * ways: - * + * * <ul> * <li>If nothing is explicitly supplied, the view ID of the container will * be used. @@ -318,7 +322,7 @@ final class FragmentState implements Parcelable { * <li><code>android:id</code> can be used in <fragment> to provide * a specific identifier for the fragment. * </ul> - * + * * <a name="BackStack"></a> * <h3>Back Stack</h3> * @@ -347,7 +351,7 @@ final class FragmentState implements Parcelable { public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener { private static final ArrayMap<String, Class<?>> sClassMap = new ArrayMap<String, Class<?>>(); - + static final int INVALID_STATE = -1; // Invalid state used as a null value. static final int INITIALIZING = 0; // Not yet created. static final int CREATED = 1; // Created. @@ -355,9 +359,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene static final int STOPPED = 3; // Fully created, not started. static final int STARTED = 4; // Created and started, not resumed. static final int RESUMED = 5; // Created started and resumed. - + + private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet(); + int mState = INITIALIZING; - + // Non-null if the fragment's view hierarchy is currently animating away, // meaning we need to wait a bit on completely destroying it. This is the // animation that is running. @@ -370,13 +376,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // When instantiated from saved state, this is the saved state. Bundle mSavedFragmentState; SparseArray<Parcelable> mSavedViewState; - + // Index into active fragment array. int mIndex = -1; - + // Internal unique name for this fragment; String mWho; - + // Construction arguments; Bundle mArguments; @@ -391,25 +397,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // True if the fragment is in the list of added fragments. boolean mAdded; - + // If set this fragment is being removed from its activity. boolean mRemoving; // True if the fragment is in the resumed state. boolean mResumed; - + // Set to true if this fragment was instantiated from a layout file. boolean mFromLayout; - + // Set to true when the view has actually been inflated in its layout. boolean mInLayout; // True if this fragment has been restored from previously saved state. boolean mRestored; - + // Number of active back stack entries this fragment is in. int mBackStackNesting; - + // The fragment manager we are associated with. Set as soon as the // fragment is used in a transaction; cleared after it has been removed // from all transactions. @@ -428,29 +434,29 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // was dynamically added to the view hierarchy, or the ID supplied in // layout. int mFragmentId; - + // When a fragment is being dynamically added to the view hierarchy, this // is the identifier of the parent container it is being added to. int mContainerId; - + // The optional named tag for this fragment -- usually used to find // fragments that are not part of the layout. String mTag; - + // Set to true when the app has requested that this fragment be hidden // from the user. boolean mHidden; - + // Set to true when the app has requested that this fragment be detached. boolean mDetached; // If set this fragment would like its instance retained across // configuration changes. boolean mRetainInstance; - + // If set this fragment is being retained across the current config change. boolean mRetaining; - + // If set this fragment has menu items to contribute. boolean mHasMenu; @@ -459,16 +465,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // Used to verify that subclasses call through to super class. boolean mCalled; - + // If app has requested a specific animation, this is the one to use. int mNextAnim; - + // The parent container of the fragment after dynamically added to UI. ViewGroup mContainer; - + // The View generated for this fragment. View mView; - + // Whether this fragment should defer starting until after other fragments // have been started and their loaders are finished. boolean mDeferStart; @@ -479,7 +485,19 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene LoaderManagerImpl mLoaderManager; boolean mLoadersStarted; boolean mCheckedForLoaderManager; - + + private Transition mEnterTransition = null; + private Transition mReturnTransition = USE_DEFAULT_TRANSITION; + private Transition mExitTransition = null; + private Transition mReenterTransition = USE_DEFAULT_TRANSITION; + private Transition mSharedElementEnterTransition = null; + private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION; + private Boolean mAllowReturnTransitionOverlap; + private Boolean mAllowEnterTransitionOverlap; + + SharedElementCallback mEnterTransitionCallback = SharedElementCallback.NULL_CALLBACK; + SharedElementCallback mExitTransitionCallback = SharedElementCallback.NULL_CALLBACK; + /** * State information that has been retrieved from a fragment instance * through {@link FragmentManager#saveFragmentInstanceState(Fragment) @@ -543,7 +561,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * will not be called when the fragment is re-instantiated; instead, * arguments can be supplied by the caller with {@link #setArguments} * and later retrieved by the Fragment with {@link #getArguments}. - * + * * <p>Applications should generally not implement a constructor. The * first place application code an run where the fragment is ready to * be used is in {@link #onAttach(Activity)}, the point where the fragment @@ -609,7 +627,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene + " empty constructor that is public", e); } } - + final void restoreViewState(Bundle savedInstanceState) { if (mSavedViewState != null) { mView.restoreHierarchyState(mSavedViewState); @@ -649,7 +667,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene @Override final public int hashCode() { return super.hashCode(); } - + @Override public String toString() { StringBuilder sb = new StringBuilder(128); @@ -669,7 +687,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene sb.append('}'); return sb.toString(); } - + /** * Return the identifier this fragment is known by. This is either * the android:id value supplied in a layout or the container view ID @@ -678,14 +696,14 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public int getId() { return mFragmentId; } - + /** * Get the tag name of the fragment, if specified. */ final public String getTag() { return mTag; } - + /** * Supply the construction arguments for this fragment. This can only * be called before the fragment has been attached to its activity; that @@ -760,7 +778,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public Activity getActivity() { return mActivity; } - + /** * Return <code>getActivity().getResources()</code>. */ @@ -770,7 +788,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } return mActivity.getResources(); } - + /** * Return a localized, styled CharSequence from the application's package's * default string table. @@ -870,7 +888,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public boolean isRemoving() { return mRemoving; } - + /** * Return true if the layout is included as part of an activity view * hierarchy via the <fragment> tag. This will always be true when @@ -889,7 +907,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public boolean isResumed() { return mResumed; } - + /** * Return true if the fragment is currently visible to the user. This means * it: (1) has been added, (2) has its view attached to the window, and @@ -899,7 +917,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene return isAdded() && !isHidden() && mView != null && mView.getWindowToken() != null && mView.getVisibility() == View.VISIBLE; } - + /** * Return true if the fragment has been hidden. By default fragments * are shown. You can find out about changes to this state with @@ -910,7 +928,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final public boolean isHidden() { return mHidden; } - + /** * Called when the hidden state (as returned by {@link #isHidden()} of * the fragment has changed. Fragments start out not hidden; this will @@ -920,7 +938,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onHiddenChanged(boolean hidden) { } - + /** * Control whether a fragment instance is retained across Activity * re-creation (such as from a configuration change). This can only @@ -942,16 +960,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } mRetainInstance = retain; } - + final public boolean getRetainInstance() { return mRetainInstance; } - + /** * Report that this fragment would like to participate in populating * the options menu by receiving a call to {@link #onCreateOptionsMenu} * and related methods. - * + * * @param hasMenu If true, the fragment has menu items to contribute. */ public void setHasOptionsMenu(boolean hasMenu) { @@ -1034,7 +1052,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void startActivity(Intent intent) { startActivity(intent, null); } - + /** * Call {@link Activity#startActivity(Intent, Bundle)} from the fragment's * containing Activity. @@ -1081,13 +1099,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mActivity.startActivityFromFragment(this, intent, requestCode, options); } } - + /** * Receive the result from a previous call to * {@link #startActivityForResult(Intent, int)}. This follows the * related Activity API as described there in * {@link Activity#onActivityResult(int, int, Intent)}. - * + * * @param requestCode The integer request code originally supplied to * startActivityForResult(), allowing you to identify who this * result came from. @@ -1098,7 +1116,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onActivityResult(int requestCode, int resultCode, Intent data) { } - + /** * @hide Hack so that DialogFragment can make its Dialog before creating * its views, and the view construction can use the dialog's context for @@ -1115,7 +1133,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene return mActivity.getLayoutInflater(); } } - + /** * @deprecated Use {@link #onInflate(Activity, AttributeSet, Bundle)} instead. */ @@ -1131,7 +1149,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * tag in a layout file. Note this is <em>before</em> the fragment's * {@link #onAttach(Activity)} has been called; all you should do here is * parse the attributes and save them away. - * + * * <p>This is called every time the fragment is inflated, even if it is * being inflated into a new instance with saved state. It typically makes * sense to re-parse the parameters each time, to allow them to change with @@ -1169,8 +1187,33 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) { onInflate(attrs, savedInstanceState); mCalled = true; + + TypedArray a = activity.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.Fragment); + mEnterTransition = loadTransition(activity, a, mEnterTransition, null, + com.android.internal.R.styleable.Fragment_fragmentEnterTransition); + mReturnTransition = loadTransition(activity, a, mReturnTransition, USE_DEFAULT_TRANSITION, + com.android.internal.R.styleable.Fragment_fragmentReturnTransition); + mExitTransition = loadTransition(activity, a, mExitTransition, null, + com.android.internal.R.styleable.Fragment_fragmentExitTransition); + mReenterTransition = loadTransition(activity, a, mReenterTransition, USE_DEFAULT_TRANSITION, + com.android.internal.R.styleable.Fragment_fragmentReenterTransition); + mSharedElementEnterTransition = loadTransition(activity, a, mSharedElementEnterTransition, + null, com.android.internal.R.styleable.Fragment_fragmentSharedElementEnterTransition); + mSharedElementReturnTransition = loadTransition(activity, a, mSharedElementReturnTransition, + USE_DEFAULT_TRANSITION, + com.android.internal.R.styleable.Fragment_fragmentSharedElementReturnTransition); + if (mAllowEnterTransitionOverlap == null) { + mAllowEnterTransitionOverlap = a.getBoolean( + com.android.internal.R.styleable.Fragment_fragmentAllowEnterTransitionOverlap, true); + } + if (mAllowReturnTransitionOverlap == null) { + mAllowReturnTransitionOverlap = a.getBoolean( + com.android.internal.R.styleable.Fragment_fragmentAllowReturnTransitionOverlap, true); + } + a.recycle(); } - + /** * Called when a fragment is first attached to its activity. * {@link #onCreate(Bundle)} will be called after this. @@ -1178,25 +1221,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onAttach(Activity activity) { mCalled = true; } - + /** * Called when a fragment loads an animation. */ public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) { return null; } - + /** * Called to do initial creation of a fragment. This is called after * {@link #onAttach(Activity)} and before * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}. - * + * * <p>Note that this can be called while the fragment's activity is * still in the process of being created. As such, you can not rely * on things like the activity's content view hierarchy being initialized * at this point. If you want to do work once the activity itself is * created, see {@link #onActivityCreated(Bundle)}. - * + * * @param savedInstanceState If the fragment is being re-created from * a previous saved state, this is the state. */ @@ -1209,10 +1252,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * This is optional, and non-graphical fragments can return null (which * is the default implementation). This will be called between * {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}. - * + * * <p>If you return a View from here, you will later be called in * {@link #onDestroyView} when the view is being released. - * + * * @param inflater The LayoutInflater object that can be used to inflate * any views in the fragment, * @param container If non-null, this is the parent view that the fragment's @@ -1220,7 +1263,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * but this can be used to generate the LayoutParams of the view. * @param savedInstanceState If non-null, this fragment is being re-constructed * from a previous saved state as given here. - * + * * @return Return the View for the fragment's UI, or null. */ @Nullable @@ -1241,18 +1284,18 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { } - + /** * Get the root view for the fragment's layout (the one returned by {@link #onCreateView}), * if provided. - * + * * @return The fragment's root view, or null if it has no layout. */ @Nullable public View getView() { return mView; } - + /** * Called when the fragment's activity has been created and this * fragment's view hierarchy instantiated. It can be used to do final @@ -1292,7 +1335,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onStart() { mCalled = true; - + if (!mLoadersStarted) { mLoadersStarted = true; if (!mCheckedForLoaderManager) { @@ -1304,7 +1347,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } } } - + /** * Called when the fragment is visible to the user and actively running. * This is generally @@ -1314,7 +1357,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onResume() { mCalled = true; } - + /** * Called to ask the fragment to save its current dynamic state, so it * can later be reconstructed in a new instance of its process is @@ -1336,11 +1379,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onSaveInstanceState(Bundle outState) { } - + public void onConfigurationChanged(Configuration newConfig) { mCalled = true; } - + /** * Called when the Fragment is no longer resumed. This is generally * tied to {@link Activity#onPause() Activity.onPause} of the containing @@ -1349,7 +1392,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onPause() { mCalled = true; } - + /** * Called when the Fragment is no longer started. This is generally * tied to {@link Activity#onStop() Activity.onStop} of the containing @@ -1358,11 +1401,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onStop() { mCalled = true; } - + public void onLowMemory() { mCalled = true; } - + public void onTrimMemory(int level) { mCalled = true; } @@ -1379,7 +1422,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onDestroyView() { mCalled = true; } - + /** * Called when the fragment is no longer in use. This is called * after {@link #onStop()} and before {@link #onDetach()}. @@ -1434,16 +1477,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public void onDetach() { mCalled = true; } - + /** * Initialize the contents of the Activity's standard options menu. You * should place your menu items in to <var>menu</var>. For this method * to be called, you must have first called {@link #setHasOptionsMenu}. See * {@link Activity#onCreateOptionsMenu(Menu) Activity.onCreateOptionsMenu} * for more information. - * + * * @param menu The options menu in which you place your items. - * + * * @see #setHasOptionsMenu * @see #onPrepareOptionsMenu * @see #onOptionsItemSelected @@ -1458,10 +1501,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * dynamically modify the contents. See * {@link Activity#onPrepareOptionsMenu(Menu) Activity.onPrepareOptionsMenu} * for more information. - * + * * @param menu The options menu as last shown or first initialized by * onCreateOptionsMenu(). - * + * * @see #setHasOptionsMenu * @see #onCreateOptionsMenu */ @@ -1477,7 +1520,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onDestroyOptionsMenu() { } - + /** * This hook is called whenever an item in your options menu is selected. * The default implementation simply returns false to have the normal @@ -1485,15 +1528,15 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * its Handler as appropriate). You can use this method for any items * for which you would like to do processing without those other * facilities. - * + * * <p>Derived classes should call through to the base class for it to * perform the default menu handling. - * + * * @param item The menu item that was selected. - * + * * @return boolean Return false to allow normal menu processing to * proceed, true to consume it here. - * + * * @see #onCreateOptionsMenu */ public boolean onOptionsItemSelected(MenuItem item) { @@ -1503,13 +1546,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene /** * This hook is called whenever the options menu is being closed (either by the user canceling * the menu with the back/menu button, or when an item is selected). - * + * * @param menu The options menu as last shown or first initialized by * onCreateOptionsMenu(). */ public void onOptionsMenuClosed(Menu menu) { } - + /** * Called when a context menu for the {@code view} is about to be shown. * Unlike {@link #onCreateOptionsMenu}, this will be called every @@ -1537,25 +1580,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * {@link OnCreateContextMenuListener} on the view to this fragment, so * {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} will be * called when it is time to show the context menu. - * + * * @see #unregisterForContextMenu(View) * @param view The view that should show a context menu. */ public void registerForContextMenu(View view) { view.setOnCreateContextMenuListener(this); } - + /** * Prevents a context menu to be shown for the given view. This method will * remove the {@link OnCreateContextMenuListener} on the view. - * + * * @see #registerForContextMenu(View) * @param view The view that should stop showing a context menu. */ public void unregisterForContextMenu(View view) { view.setOnCreateContextMenuListener(null); } - + /** * This hook is called whenever an item in a context menu is selected. The * default implementation simply returns false to have the normal processing @@ -1568,7 +1611,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * <p> * Derived classes should call through to the base class for it to perform * the default menu handling. - * + * * @param item The context menu item that was selected. * @return boolean Return false to allow normal context menu processing to * proceed, true to consume it here. @@ -1576,7 +1619,284 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene public boolean onContextItemSelected(MenuItem item) { return false; } - + + /** + * When custom transitions are used with Fragments, the enter transition callback + * is called when this Fragment is attached or detached when not popping the back stack. + * + * @param callback Used to manipulate the shared element transitions on this Fragment + * when added not as a pop from the back stack. + */ + public void setEnterSharedElementTransitionCallback(SharedElementCallback callback) { + if (callback == null) { + callback = SharedElementCallback.NULL_CALLBACK; + } + mEnterTransitionCallback = callback; + } + + /** + * When custom transitions are used with Fragments, the exit transition callback + * is called when this Fragment is attached or detached when popping the back stack. + * + * @param callback Used to manipulate the shared element transitions on this Fragment + * when added as a pop from the back stack. + */ + public void setExitSharedElementTransitionCallback(SharedElementCallback callback) { + if (callback == null) { + callback = SharedElementCallback.NULL_CALLBACK; + } + mExitTransitionCallback = callback; + } + + /** + * Sets the Transition that will be used to move Views into the initial scene. The entering + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null, + * entering Views will remain unaffected. + * + * @param transition The Transition to use to move Views into the initial Scene. + * @attr ref android.R.styleable#Fragment_fragmentEnterTransition + */ + public void setEnterTransition(Transition transition) { + mEnterTransition = transition; + } + + /** + * Returns the Transition that will be used to move Views into the initial scene. The entering + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#INVISIBLE} to {@link View#VISIBLE}. + * + * @return the Transition to use to move Views into the initial Scene. + * @attr ref android.R.styleable#Fragment_fragmentEnterTransition + */ + public Transition getEnterTransition() { + return mEnterTransition; + } + + /** + * Sets the Transition that will be used to move Views out of the scene when the Fragment is + * preparing to be removed, hidden, or detached because of popping the back stack. The exiting + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null, + * entering Views will remain unaffected. If nothing is set, the default will be to + * use the same value as set in {@link #setEnterTransition(android.transition.Transition)}. + * + * @param transition The Transition to use to move Views out of the Scene when the Fragment + * is preparing to close. + * @attr ref android.R.styleable#Fragment_fragmentExitTransition + */ + public void setReturnTransition(Transition transition) { + mReturnTransition = transition; + } + + /** + * Returns the Transition that will be used to move Views out of the scene when the Fragment is + * preparing to be removed, hidden, or detached because of popping the back stack. The exiting + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null, + * entering Views will remain unaffected. + * + * @return the Transition to use to move Views out of the Scene when the Fragment + * is preparing to close. + * @attr ref android.R.styleable#Fragment_fragmentExitTransition + */ + public Transition getReturnTransition() { + return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition() + : mReturnTransition; + } + + /** + * Sets the Transition that will be used to move Views out of the scene when the + * fragment is removed, hidden, or detached when not popping the back stack. + * The exiting Views will be those that are regular Views or ViewGroups that + * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as exiting is governed by changing visibility + * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will + * remain unaffected. + * + * @param transition The Transition to use to move Views out of the Scene when the Fragment + * is being closed not due to popping the back stack. + * @attr ref android.R.styleable#Fragment_fragmentExitTransition + */ + public void setExitTransition(Transition transition) { + mExitTransition = transition; + } + + /** + * Returns the Transition that will be used to move Views out of the scene when the + * fragment is removed, hidden, or detached when not popping the back stack. + * The exiting Views will be those that are regular Views or ViewGroups that + * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as exiting is governed by changing visibility + * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will + * remain unaffected. + * + * @return the Transition to use to move Views out of the Scene when the Fragment + * is being closed not due to popping the back stack. + * @attr ref android.R.styleable#Fragment_fragmentExitTransition + */ + public Transition getExitTransition() { + return mExitTransition; + } + + /** + * Sets the Transition that will be used to move Views in to the scene when returning due + * to popping a back stack. The entering Views will be those that are regular Views + * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions + * will extend {@link android.transition.Visibility} as exiting is governed by changing + * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, + * the views will remain unaffected. If nothing is set, the default will be to use the same + * transition as {@link #setExitTransition(android.transition.Transition)}. + * + * @param transition The Transition to use to move Views into the scene when reentering from a + * previously-started Activity. + * @attr ref android.R.styleable#Fragment_fragmentReenterTransition + */ + public void setReenterTransition(Transition transition) { + mReenterTransition = transition; + } + + /** + * Returns the Transition that will be used to move Views in to the scene when returning due + * to popping a back stack. The entering Views will be those that are regular Views + * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions + * will extend {@link android.transition.Visibility} as exiting is governed by changing + * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, + * the views will remain unaffected. If nothing is set, the default will be to use the same + * transition as {@link #setExitTransition(android.transition.Transition)}. + * + * @return the Transition to use to move Views into the scene when reentering from a + * previously-started Activity. + * @attr ref android.R.styleable#Fragment_fragmentReenterTransition + */ + public Transition getReenterTransition() { + return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition() + : mReenterTransition; + } + + /** + * Sets the Transition that will be used for shared elements transferred into the content + * Scene. Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * + * @param transition The Transition to use for shared elements transferred into the content + * Scene. + * @attr ref android.R.styleable#Fragment_fragmentSharedElementEnterTransition + */ + public void setSharedElementEnterTransition(Transition transition) { + mSharedElementEnterTransition = transition; + } + + /** + * Returns the Transition that will be used for shared elements transferred into the content + * Scene. Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * + * @return The Transition to use for shared elements transferred into the content + * Scene. + * @attr ref android.R.styleable#Fragment_fragmentSharedElementEnterTransition + */ + public Transition getSharedElementEnterTransition() { + return mSharedElementEnterTransition; + } + + /** + * Sets the Transition that will be used for shared elements transferred back during a + * pop of the back stack. This Transition acts in the leaving Fragment. + * Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * If no value is set, the default will be to use the same value as + * {@link #setSharedElementEnterTransition(android.transition.Transition)}. + * + * @param transition The Transition to use for shared elements transferred out of the content + * Scene. + * @attr ref android.R.styleable#Fragment_fragmentSharedElementReturnTransition + */ + public void setSharedElementReturnTransition(Transition transition) { + mSharedElementReturnTransition = transition; + } + + /** + * Return the Transition that will be used for shared elements transferred back during a + * pop of the back stack. This Transition acts in the leaving Fragment. + * Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * If no value is set, the default will be to use the same value as + * {@link #setSharedElementEnterTransition(android.transition.Transition)}. + * + * @return The Transition to use for shared elements transferred out of the content + * Scene. + * @attr ref android.R.styleable#Fragment_fragmentSharedElementReturnTransition + */ + public Transition getSharedElementReturnTransition() { + return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION ? + getSharedElementEnterTransition() : mSharedElementReturnTransition; + } + + /** + * Sets whether the the exit transition and enter transition overlap or not. + * When true, the enter transition will start as soon as possible. When false, the + * enter transition will wait until the exit transition completes before starting. + * + * @param allow true to start the enter transition when possible or false to + * wait until the exiting transition completes. + * @attr ref android.R.styleable#Fragment_fragmentAllowEnterTransitionOverlap + */ + public void setAllowEnterTransitionOverlap(boolean allow) { + mAllowEnterTransitionOverlap = allow; + } + + /** + * Returns whether the the exit transition and enter transition overlap or not. + * When true, the enter transition will start as soon as possible. When false, the + * enter transition will wait until the exit transition completes before starting. + * + * @return true when the enter transition should start as soon as possible or false to + * when it should wait until the exiting transition completes. + * @attr ref android.R.styleable#Fragment_fragmentAllowEnterTransitionOverlap + */ + public boolean getAllowEnterTransitionOverlap() { + return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap; + } + + /** + * Sets whether the the return transition and reenter transition overlap or not. + * When true, the reenter transition will start as soon as possible. When false, the + * reenter transition will wait until the return transition completes before starting. + * + * @param allow true to start the reenter transition when possible or false to wait until the + * return transition completes. + * @attr ref android.R.styleable#Fragment_fragmentAllowReturnTransitionOverlap + */ + public void setAllowReturnTransitionOverlap(boolean allow) { + mAllowReturnTransitionOverlap = allow; + } + + /** + * Returns whether the the return transition and reenter transition overlap or not. + * When true, the reenter transition will start as soon as possible. When false, the + * reenter transition will wait until the return transition completes before starting. + * + * @return true to start the reenter transition when possible or false to wait until the + * return transition completes. + * @attr ref android.R.styleable#Fragment_fragmentAllowReturnTransitionOverlap + */ + public boolean getAllowReturnTransitionOverlap() { + return (mAllowReturnTransitionOverlap == null) ? true : mAllowReturnTransitionOverlap; + } + /** * Print the Fragments's state into the given stream. * @@ -1588,53 +1908,53 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { writer.print(prefix); writer.print("mFragmentId=#"); - writer.print(Integer.toHexString(mFragmentId)); - writer.print(" mContainerId=#"); - writer.print(Integer.toHexString(mContainerId)); - writer.print(" mTag="); writer.println(mTag); + writer.print(Integer.toHexString(mFragmentId)); + writer.print(" mContainerId=#"); + writer.print(Integer.toHexString(mContainerId)); + writer.print(" mTag="); writer.println(mTag); writer.print(prefix); writer.print("mState="); writer.print(mState); - writer.print(" mIndex="); writer.print(mIndex); - writer.print(" mWho="); writer.print(mWho); - writer.print(" mBackStackNesting="); writer.println(mBackStackNesting); + writer.print(" mIndex="); writer.print(mIndex); + writer.print(" mWho="); writer.print(mWho); + writer.print(" mBackStackNesting="); writer.println(mBackStackNesting); writer.print(prefix); writer.print("mAdded="); writer.print(mAdded); - writer.print(" mRemoving="); writer.print(mRemoving); - writer.print(" mResumed="); writer.print(mResumed); - writer.print(" mFromLayout="); writer.print(mFromLayout); - writer.print(" mInLayout="); writer.println(mInLayout); + writer.print(" mRemoving="); writer.print(mRemoving); + writer.print(" mResumed="); writer.print(mResumed); + writer.print(" mFromLayout="); writer.print(mFromLayout); + writer.print(" mInLayout="); writer.println(mInLayout); writer.print(prefix); writer.print("mHidden="); writer.print(mHidden); - writer.print(" mDetached="); writer.print(mDetached); - writer.print(" mMenuVisible="); writer.print(mMenuVisible); - writer.print(" mHasMenu="); writer.println(mHasMenu); + writer.print(" mDetached="); writer.print(mDetached); + writer.print(" mMenuVisible="); writer.print(mMenuVisible); + writer.print(" mHasMenu="); writer.println(mHasMenu); writer.print(prefix); writer.print("mRetainInstance="); writer.print(mRetainInstance); - writer.print(" mRetaining="); writer.print(mRetaining); - writer.print(" mUserVisibleHint="); writer.println(mUserVisibleHint); + writer.print(" mRetaining="); writer.print(mRetaining); + writer.print(" mUserVisibleHint="); writer.println(mUserVisibleHint); if (mFragmentManager != null) { writer.print(prefix); writer.print("mFragmentManager="); - writer.println(mFragmentManager); + writer.println(mFragmentManager); } if (mActivity != null) { writer.print(prefix); writer.print("mActivity="); - writer.println(mActivity); + writer.println(mActivity); } if (mParentFragment != null) { writer.print(prefix); writer.print("mParentFragment="); - writer.println(mParentFragment); + writer.println(mParentFragment); } if (mArguments != null) { writer.print(prefix); writer.print("mArguments="); writer.println(mArguments); } if (mSavedFragmentState != null) { writer.print(prefix); writer.print("mSavedFragmentState="); - writer.println(mSavedFragmentState); + writer.println(mSavedFragmentState); } if (mSavedViewState != null) { writer.print(prefix); writer.print("mSavedViewState="); - writer.println(mSavedViewState); + writer.println(mSavedViewState); } if (mTarget != null) { writer.print(prefix); writer.print("mTarget="); writer.print(mTarget); - writer.print(" mTargetRequestCode="); - writer.println(mTargetRequestCode); + writer.print(" mTargetRequestCode="); + writer.println(mTargetRequestCode); } if (mNextAnim != 0) { writer.print(prefix); writer.print("mNextAnim="); writer.println(mNextAnim); @@ -1648,7 +1968,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene if (mAnimatingAway != null) { writer.print(prefix); writer.print("mAnimatingAway="); writer.println(mAnimatingAway); writer.print(prefix); writer.print("mStateAfterAnimating="); - writer.println(mStateAfterAnimating); + writer.println(mStateAfterAnimating); } if (mLoaderManager != null) { writer.print(prefix); writer.println("Loader Manager:"); @@ -1886,7 +2206,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene throw new SuperNotCalledException("Fragment " + this + " did not call through to super.onStop()"); } - + if (mLoadersStarted) { mLoadersStarted = false; if (!mCheckedForLoaderManager) { @@ -1929,4 +2249,23 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene + " did not call through to super.onDestroy()"); } } + + private static Transition loadTransition(Context context, TypedArray typedArray, + Transition currentValue, Transition defaultValue, int id) { + if (currentValue != defaultValue) { + return currentValue; + } + int transitionId = typedArray.getResourceId(id, 0); + Transition transition = defaultValue; + if (transitionId != 0 && transitionId != com.android.internal.R.transition.no_transition) { + TransitionInflater inflater = TransitionInflater.from(context); + transition = inflater.inflateTransition(transitionId); + if (transition instanceof TransitionSet && + ((TransitionSet)transition).getTransitionCount() == 0) { + transition = null; + } + } + return transition; + } + } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 1df1d42..ef69fdd 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1497,7 +1497,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate return false; } final BackStackRecord bss = mBackStack.remove(last); - bss.popFromBackStack(true, null); + SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>(); + SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>(); + bss.calculateBackFragments(firstOutFragments, lastInFragments); + bss.popFromBackStack(true, null, firstOutFragments, lastInFragments); reportBackStackChanged(); } else { int index = -1; @@ -1541,10 +1544,16 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate states.add(mBackStack.remove(i)); } final int LAST = states.size()-1; + SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>(); + SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>(); + for (int i=0; i<=LAST; i++) { + states.get(i).calculateBackFragments(firstOutFragments, lastInFragments); + } BackStackRecord.TransitionState state = null; for (int i=0; i<=LAST; i++) { if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i)); - state = states.get(i).popFromBackStack(i == LAST, state); + state = states.get(i).popFromBackStack(i == LAST, state, + firstOutFragments, lastInFragments); } reportBackStackChanged(); } diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java index 1077bac..25cd3cc 100644 --- a/core/java/android/app/FragmentTransaction.java +++ b/core/java/android/app/FragmentTransaction.java @@ -172,19 +172,16 @@ public abstract class FragmentTransaction { public abstract FragmentTransaction setTransition(int transit); /** - * Set a {@link android.transition.Transition} resource id to use with this transaction. - * <var>transitionId</var> will be played for fragments when going forward and when popping - * the back stack. - * @param sceneRootId The ID of the element acting as the scene root for the transition. - * This should be a ViewGroup containing all Fragments in the transaction. - * @param transitionId The resource ID for the Transition used during the Fragment transaction. + * TODO: remove from API + * @hide */ - public abstract FragmentTransaction setCustomTransition(int sceneRootId, int transitionId); + public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) { + return this; + } /** - * Used with {@link #setCustomTransition(int, int)} to map a View from a removed or hidden - * Fragment to a View from a shown or added Fragment. - * <var>sharedElement</var> must have a unique transitionName in the View hierarchy. + * Used with to map a View from a removed or hidden Fragment to a View from a shown + * or added Fragment. * @param sharedElement A View in a disappearing Fragment to match with a View in an * appearing Fragment. * @param name The transitionName for a View in an appearing Fragment to match to the shared diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index dbd180f..7d4512b 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -48,6 +48,9 @@ interface INotificationManager void setPackagePriority(String pkg, int uid, int priority); int getPackagePriority(String pkg, int uid); + void setPackageVisibilityOverride(String pkg, int uid, int visibility); + int getPackageVisibilityOverride(String pkg, int uid); + // TODO: Remove this when callers have been migrated to the equivalent // INotificationListener method. StatusBarNotification[] getActiveNotifications(String callingPkg); @@ -68,6 +71,7 @@ interface INotificationManager ComponentName getEffectsSuppressor(); boolean matchesCallFilter(in Bundle extras); + boolean matchesCallFilterAsUser(in Bundle extras, int userId); ZenModeConfig getZenModeConfig(); boolean setZenModeConfig(in ZenModeConfig config); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 800734a..f8dfdd9 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -21,6 +21,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -129,6 +130,14 @@ public class Notification implements Parcelable public static final int DEFAULT_LIGHTS = 4; /** + * Maximum length of CharSequences accepted by Builder and friends. + * + * <p> + * Avoids spamming the system with overly large strings such as full e-mails. + */ + private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024; + + /** * A timestamp related to this notification, in milliseconds since the epoch. * * Default value: {@link System#currentTimeMillis() Now}. @@ -816,13 +825,6 @@ public class Notification implements Parcelable public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions"; /** - * {@link #extras} key: the user that built the notification. - * - * @hide - */ - public static final String EXTRA_ORIGINATING_USERID = "android.originatingUserId"; - - /** * Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification should not be * displayed in the heads up space. * @@ -1423,6 +1425,7 @@ public class Notification implements Parcelable extras.remove(Notification.EXTRA_LARGE_ICON); extras.remove(Notification.EXTRA_LARGE_ICON_BIG); extras.remove(Notification.EXTRA_PICTURE); + extras.remove(Notification.EXTRA_BIG_TEXT); // Prevent light notifications from being rebuilt. extras.remove(Builder.EXTRA_NEEDS_REBUILD); } @@ -1434,6 +1437,10 @@ public class Notification implements Parcelable * @hide */ public static CharSequence safeCharSequence(CharSequence cs) { + if (cs == null) return cs; + if (cs.length() > MAX_CHARSEQUENCE_LENGTH) { + cs = cs.subSequence(0, MAX_CHARSEQUENCE_LENGTH); + } if (cs instanceof Parcelable) { Log.e(TAG, "warning: " + cs.getClass().getCanonicalName() + " instance is a custom Parcelable and not allowed in Notification"); @@ -1800,10 +1807,12 @@ public class Notification implements Parcelable = "android.rebuild.hudViewActionCount"; /** - * The package name of the context used to create the notification via a Builder. + * The ApplicationInfo of the package that created the notification, used to create + * a context to rebuild the notification via a Builder. + * @hide */ - private static final String EXTRA_REBUILD_CONTEXT_PACKAGE = - "android.rebuild.contextPackage"; + private static final String EXTRA_REBUILD_CONTEXT_APPLICATION_INFO = + "android.rebuild.applicationInfo"; // Whether to enable stripping (at post time) & rebuilding (at listener receive time) of // memory intensive resources. @@ -1854,11 +1863,6 @@ public class Notification implements Parcelable private int mColor = COLOR_DEFAULT; /** - * The user that built the notification originally. - */ - private int mOriginatingUserId; - - /** * Contains extras related to rebuilding during the build phase. */ private Bundle mRebuildBundle = new Bundle(); @@ -1916,7 +1920,7 @@ public class Notification implements Parcelable mPeople = new ArrayList<String>(); mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ? - NotificationColorUtil.getInstance() : null; + NotificationColorUtil.getInstance(mContext) : null; } /** @@ -2578,7 +2582,7 @@ public class Notification implements Parcelable // Note: This assumes that the current user can read the profile badge of the // originating user. UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - return userManager.getBadgeForUser(new UserHandle(mOriginatingUserId), 0); + return userManager.getBadgeForUser(new UserHandle(mContext.getUserId()), 0); } private Bitmap getProfileBadge() { @@ -2657,8 +2661,7 @@ public class Notification implements Parcelable * @param hasProgress whether the progress bar should be shown and set */ private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) { - RemoteViews contentView = new BuilderRemoteViews(mContext.getPackageName(), - mOriginatingUserId, resId); + RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId); resetStandardTemplate(contentView); @@ -2889,7 +2892,7 @@ public class Notification implements Parcelable } private void processLegacyAction(Action action, RemoteViews button) { - if (!isLegacy() || mColorUtil.isGrayscale(mContext, action.icon)) { + if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.icon)) { button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0, mContext.getResources().getColor(R.color.notification_action_color_filter), PorterDuff.Mode.MULTIPLY); @@ -2908,7 +2911,7 @@ public class Notification implements Parcelable * Apply any necessary background to smallIcons being used in the largeIcon spot. */ private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) { - if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) { + if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, largeIconId)) { applyLargeIconBackground(contentView); } } @@ -2919,7 +2922,7 @@ public class Notification implements Parcelable */ // TODO: also check bounds, transparency, that sort of thing. private void processLargeLegacyIcon(Bitmap largeIcon, RemoteViews contentView) { - if (isLegacy() && mColorUtil.isGrayscale(largeIcon)) { + if (isLegacy() && mColorUtil.isGrayscaleIcon(largeIcon)) { applyLargeIconBackground(contentView); } else { removeLargeIconBackground(contentView); @@ -2955,7 +2958,7 @@ public class Notification implements Parcelable */ private void processSmallRightIcon(int smallIconDrawableId, RemoteViews contentView) { - if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) { + if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, smallIconDrawableId)) { contentView.setDrawableParameters(R.id.right_icon, false, -1, 0xFFFFFFFF, PorterDuff.Mode.SRC_ATOP, -1); @@ -3050,8 +3053,8 @@ public class Notification implements Parcelable */ public void populateExtras(Bundle extras) { // Store original information used in the construction of this object - extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId); - extras.putString(EXTRA_REBUILD_CONTEXT_PACKAGE, mContext.getPackageName()); + extras.putParcelable(EXTRA_REBUILD_CONTEXT_APPLICATION_INFO, + mContext.getApplicationInfo()); extras.putCharSequence(EXTRA_TITLE, mContentTitle); extras.putCharSequence(EXTRA_TEXT, mContentText); extras.putCharSequence(EXTRA_SUB_TEXT, mSubText); @@ -3139,13 +3142,14 @@ public class Notification implements Parcelable extras.remove(EXTRA_NEEDS_REBUILD); // Re-create notification context so we can access app resources. - String packageName = extras.getString(EXTRA_REBUILD_CONTEXT_PACKAGE); + ApplicationInfo applicationInfo = extras.getParcelable( + EXTRA_REBUILD_CONTEXT_APPLICATION_INFO); Context builderContext; try { - builderContext = context.createPackageContext(packageName, + builderContext = context.createApplicationContext(applicationInfo, Context.CONTEXT_RESTRICTED); } catch (NameNotFoundException e) { - Log.e(TAG, "Package name " + packageName + " not found"); + Log.e(TAG, "ApplicationInfo " + applicationInfo + " not found"); builderContext = context; // try with our context } @@ -3280,7 +3284,6 @@ public class Notification implements Parcelable // Extras. Bundle extras = n.extras; - mOriginatingUserId = extras.getInt(EXTRA_ORIGINATING_USERID); mContentTitle = extras.getCharSequence(EXTRA_TITLE); mContentText = extras.getCharSequence(EXTRA_TEXT); mSubText = extras.getCharSequence(EXTRA_SUB_TEXT); @@ -3313,7 +3316,6 @@ public class Notification implements Parcelable * object. */ public Notification build() { - mOriginatingUserId = mContext.getUserId(); mHasThreeLines = hasThreeLines(); Notification n = buildUnstyled(); @@ -4813,8 +4815,8 @@ public class Notification implements Parcelable super(parcel); } - public BuilderRemoteViews(String packageName, int userId, int layoutId) { - super(packageName, userId, layoutId); + public BuilderRemoteViews(ApplicationInfo appInfo, int layoutId) { + super(appInfo, layoutId); } @Override diff --git a/core/java/android/app/SharedElementListener.java b/core/java/android/app/SharedElementCallback.java index f36d05f..82d8e5b 100644 --- a/core/java/android/app/SharedElementListener.java +++ b/core/java/android/app/SharedElementCallback.java @@ -22,7 +22,6 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; import android.os.Parcelable; import android.view.View; @@ -31,28 +30,23 @@ import java.util.Map; /** * Listener provided in - * {@link Activity#setEnterSharedElementListener(SharedElementListener)} and - * {@link Activity#setExitSharedElementListener(SharedElementListener)} - * to monitor the Activity transitions. The events can be used to customize Activity - * Transition behavior. + * {@link Activity#setEnterSharedElementCallback(SharedElementCallback)} and + * {@link Activity#setExitSharedElementCallback(SharedElementCallback)} as well as + * {@link Fragment#setEnterSharedElementTransitionCallback(SharedElementCallback)} and + * {@link Fragment#setExitSharedElementTransitionCallback(SharedElementCallback)} + * to monitor the Shared element transitions. The events can be used to customize Activity + * and Fragment Transition behavior. */ -public abstract class SharedElementListener { +public abstract class SharedElementCallback { private Matrix mTempMatrix; - static final SharedElementListener NULL_LISTENER = new SharedElementListener() { + static final SharedElementCallback NULL_CALLBACK = new SharedElementCallback() { }; /** - * Called to allow the listener to customize the start state of the shared element when - * transferring in shared element state. - * <p> - * The shared element will start at the size and position of the shared element - * in the launching Activity or Fragment. It will also transfer ImageView scaleType - * and imageMatrix if the shared elements in the calling and called Activities are - * ImageViews. Some applications may want to make additional changes, such as - * changing the clip bounds, scaling, or rotation if the shared element end state - * does not map well to the start state. - * </p> + * Called immediately after the start state is set for the shared element. + * The shared element will start at the size and position of the shared element + * in the launching Activity or Fragment. * * @param sharedElementNames The names of the shared elements that were accepted into * the View hierarchy. @@ -60,20 +54,21 @@ public abstract class SharedElementListener { * @param sharedElementSnapshots The Views containing snap shots of the shared element * from the launching Window. These elements will not * be part of the scene, but will be positioned relative - * to the Window decor View. + * to the Window decor View. This list is null for Fragment + * Transitions. */ - public void setSharedElementStart(List<String> sharedElementNames, + public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {} /** - * Called to allow the listener to customize the end state of the shared element when - * transferring in shared element state. + * Called after the end state is set for the shared element, but before the end state + * is captured by the shared element transition. * <p> * Any customization done in - * {@link #setSharedElementStart(java.util.List, java.util.List, java.util.List)} + * {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} * may need to be modified to the final state of the shared element if it is not * automatically corrected by layout. For example, rotation or scale will not - * be affected by layout and if changed in {@link #setSharedElementStart(java.util.List, + * be affected by layout and if changed in {@link #onSharedElementStart(java.util.List, * java.util.List, java.util.List)}, it will also have to be set here again to correct * the end state. * </p> @@ -84,24 +79,27 @@ public abstract class SharedElementListener { * @param sharedElementSnapshots The Views containing snap shots of the shared element * from the launching Window. These elements will not * be part of the scene, but will be positioned relative - * to the Window decor View. + * to the Window decor View. This list will be null for + * Fragment Transitions. */ - public void setSharedElementEnd(List<String> sharedElementNames, + public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {} /** - * Called after {@link #remapSharedElements(java.util.List, java.util.Map)} when + * Called after {@link #onMapSharedElements(java.util.List, java.util.Map)} when * transferring shared elements in. Any shared elements that have no mapping will be in * <var>rejectedSharedElements</var>. The elements remaining in * <var>rejectedSharedElements</var> will be transitioned out of the Scene. If a * View is removed from <var>rejectedSharedElements</var>, it must be handled by the - * <code>SharedElementListener</code>. + * <code>SharedElementCallback</code>. * <p> * Views in rejectedSharedElements will have their position and size set to the * position of the calling shared element, relative to the Window decor View and contain * snapshots of the View from the calling Activity or Fragment. This * view may be safely added to the decor View's overlay to remain in position. * </p> + * <p>This method is not called for Fragment Transitions. All rejected shared elements + * will be handled by the exit transition.</p> * * @param rejectedSharedElements Views containing visual information of shared elements * that are not part of the entering scene. These Views @@ -109,25 +107,27 @@ public abstract class SharedElementListener { * View removed from this list will not be transitioned * automatically. */ - public void handleRejectedSharedElements(List<View> rejectedSharedElements) {} + public void onRejectSharedElements(List<View> rejectedSharedElements) {} /** - * Lets the ActivityTransitionListener adjust the mapping of shared element names to + * Lets the SharedElementCallback adjust the mapping of shared element names to * Views. * * @param names The names of all shared elements transferred from the calling Activity - * to the started Activity. + * or Fragment in the order they were provided. * @param sharedElements The mapping of shared element names to Views. The best guess * will be filled into sharedElements based on the transitionNames. */ - public void remapSharedElements(List<String> names, Map<String, View> sharedElements) {} + public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {} /** * Creates a snapshot of a shared element to be used by the remote Activity and reconstituted - * with {@link #createSnapshotView(android.content.Context, android.os.Parcelable)}. A + * with {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)}. A * null return value will mean that the remote Activity will have a null snapshot View in - * {@link #setSharedElementStart(java.util.List, java.util.List, java.util.List)} and - * {@link #setSharedElementEnd(java.util.List, java.util.List, java.util.List)}. + * {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} and + * {@link #onSharedElementEnd(java.util.List, java.util.List, java.util.List)}. + * + * <p>This is not called for Fragment Transitions.</p> * * @param sharedElement The shared element View to create a snapshot for. * @param viewToGlobalMatrix A matrix containing a transform from the view to the screen @@ -135,11 +135,11 @@ public abstract class SharedElementListener { * @param screenBounds The bounds of shared element in screen coordinate space. This is * the bounds of the view with the viewToGlobalMatrix applied. * @return A snapshot to send to the remote Activity to be reconstituted with - * {@link #createSnapshotView(android.content.Context, android.os.Parcelable)} and passed - * into {@link #setSharedElementStart(java.util.List, java.util.List, java.util.List)} and - * {@link #setSharedElementEnd(java.util.List, java.util.List, java.util.List)}. + * {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)} and passed + * into {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} and + * {@link #onSharedElementEnd(java.util.List, java.util.List, java.util.List)}. */ - public Parcelable captureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, + public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, RectF screenBounds) { int bitmapWidth = Math.round(screenBounds.width()); int bitmapHeight = Math.round(screenBounds.height()); @@ -160,20 +160,22 @@ public abstract class SharedElementListener { /** * Reconstitutes a snapshot View from a Parcelable returned in - * {@link #captureSharedElementSnapshot(android.view.View, android.graphics.Matrix, - * android.graphics.RectF)} to be used in {@link #setSharedElementStart(java.util.List, - * java.util.List, java.util.List)} and {@link #setSharedElementEnd(java.util.List, + * {@link #onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, + * android.graphics.RectF)} to be used in {@link #onSharedElementStart(java.util.List, + * java.util.List, java.util.List)} and {@link #onSharedElementEnd(java.util.List, * java.util.List, java.util.List)}. The returned View will be sized and positioned after * this call so that it is ready to be added to the decor View's overlay. * + * <p>This is not called for Fragment Transitions.</p> + * * @param context The Context used to create the snapshot View. - * @param snapshot The Parcelable returned by {@link #captureSharedElementSnapshot( + * @param snapshot The Parcelable returned by {@link #onCaptureSharedElementSnapshot( * android.view.View, android.graphics.Matrix, android.graphics.RectF)}. - * @return A View to be sent in {@link #setSharedElementStart(java.util.List, java.util.List, - * java.util.List)} and {@link #setSharedElementEnd(java.util.List, java.util.List, + * @return A View to be sent in {@link #onSharedElementStart(java.util.List, java.util.List, + * java.util.List)} and {@link #onSharedElementEnd(java.util.List, java.util.List, * java.util.List)}. A null value will produce a null snapshot value for those two methods. */ - public View createSnapshotView(Context context, Parcelable snapshot) { + public View onCreateSnapshotView(Context context, Parcelable snapshot) { View view = null; if (snapshot instanceof Bitmap) { Bitmap bitmap = (Bitmap) snapshot; diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 15def09..e2f175c 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -177,7 +177,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_LOCK_TASK_ENTERING - = "android.app.action.ACTION_LOCK_TASK_ENTERING"; + = "android.app.action.LOCK_TASK_ENTERING"; /** * Action sent to a device administrator to notify that the device is exiting @@ -190,7 +190,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_LOCK_TASK_EXITING - = "android.app.action.ACTION_LOCK_TASK_EXITING"; + = "android.app.action.LOCK_TASK_EXITING"; /** * A boolean describing whether the device is currently entering or exiting diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 69b1139..112fc82 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -115,6 +115,19 @@ public class DevicePolicyManager { = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE"; /** + * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that allows + * a mobile device management application that starts managed profile provisioning to pass data + * to itself on the managed profile when provisioning completes. The mobile device management + * application sends this extra in an intent with the action + * {@link #ACTION_PROVISION_MANAGED_PROFILE} and receives it in + * {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with the action + * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is not changed + * during the managed profile provisioning. + */ + public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = + "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"; + + /** * A String extra holding the package name of the mobile device management application that * will be set as the profile owner or device owner. * @@ -135,21 +148,15 @@ public class DevicePolicyManager { * <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} */ public static final String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME - = "android.app.extra.DEFAULT_MANAGED_PROFILE_NAME"; + = "android.app.extra.PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME"; /** - * A String extra that, holds the email address of the account which a managed profile is - * created for. Used with {@link #ACTION_PROVISION_MANAGED_PROFILE} and - * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. - * - * <p> If the {@link #ACTION_PROVISION_MANAGED_PROFILE} intent that starts managed provisioning - * contains this extra, it is forwarded in the - * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} intent to the mobile - * device management application that was set as the profile owner during provisioning. - * It is usually used to avoid that the user has to enter their email address twice. + * A bundle key, used in the bundle extra {@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}. The + * corresponding value holds the email address of the account which the managed profile is + * created for. */ - public static final String EXTRA_PROVISIONING_EMAIL_ADDRESS - = "android.app.extra.ManagedProfileEmailAddress"; + public static final String KEY_PROVISIONING_EMAIL_ADDRESS + = "android.app.key.PROVISIONING_EMAIL_ADDRESS"; /** * A String extra holding the time zone {@link android.app.AlarmManager} that the device @@ -159,7 +166,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_TIME_ZONE - = "android.app.extra.TIME_ZONE"; + = "android.app.extra.PROVISIONING_TIME_ZONE"; /** * A Long extra holding the wall clock time (in milliseconds) to be set on the device's @@ -169,7 +176,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_LOCAL_TIME - = "android.app.extra.LOCAL_TIME"; + = "android.app.extra.PROVISIONING_LOCAL_TIME"; /** * A String extra holding the {@link java.util.Locale} that the device will be set to. @@ -179,7 +186,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_LOCALE - = "android.app.extra.LOCALE"; + = "android.app.extra.PROVISIONING_LOCALE"; /** * A String extra holding the ssid of the wifi network that should be used during nfc device @@ -189,7 +196,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_SSID - = "android.app.extra.WIFI_SSID"; + = "android.app.extra.PROVISIONING_WIFI_SSID"; /** * A boolean extra indicating whether the wifi network in {@link #EXTRA_PROVISIONING_WIFI_SSID} @@ -199,7 +206,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_HIDDEN - = "android.app.extra.WIFI_HIDDEN"; + = "android.app.extra.PROVISIONING_WIFI_HIDDEN"; /** * A String extra indicating the security type of the wifi network in @@ -209,7 +216,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE - = "android.app.extra.WIFI_SECURITY_TYPE"; + = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE"; /** * A String extra holding the password of the wifi network in @@ -219,7 +226,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PASSWORD - = "android.app.extra.WIFI_PASSWORD"; + = "android.app.extra.PROVISIONING_WIFI_PASSWORD"; /** * A String extra holding the proxy host for the wifi network in @@ -229,7 +236,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PROXY_HOST - = "android.app.extra.WIFI_PROXY_HOST"; + = "android.app.extra.PROVISIONING_WIFI_PROXY_HOST"; /** * An int extra holding the proxy port for the wifi network in @@ -239,7 +246,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PROXY_PORT - = "android.app.extra.WIFI_PROXY_PORT"; + = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT"; /** * A String extra holding the proxy bypass for the wifi network in @@ -249,7 +256,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS - = "android.app.extra.WIFI_PROXY_BYPASS_HOSTS"; + = "android.app.extra.PROVISIONING_WIFI_PROXY_BYPASS"; /** * A String extra holding the proxy auto-config (PAC) URL for the wifi network in @@ -259,7 +266,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PAC_URL - = "android.app.extra.WIFI_PAC_URL"; + = "android.app.extra.PROVISIONING_WIFI_PAC_URL"; /** * A String extra holding a url that specifies the download location of the device admin @@ -269,7 +276,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION - = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION"; + = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION"; /** * A String extra holding a http cookie header which should be used in the http request to the @@ -279,7 +286,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER - = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; + = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; /** * A String extra holding the SHA-1 checksum of the file at download location specified in @@ -291,7 +298,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM - = "android.app.extra.DEVICE_ADMIN_PACKAGE_CHECKSUM"; + = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM"; /** * This MIME type is used for starting the Device Owner provisioning. @@ -1773,16 +1780,24 @@ public class DevicePolicyManager { * If a user has installed any certificates by other means than device policy these will be * included too. * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return a List of byte[] arrays, each encoding one user CA certificate. */ - public List<byte[]> getInstalledCaCerts() { - final TrustedCertificateStore certStore = new TrustedCertificateStore(); + public List<byte[]> getInstalledCaCerts(ComponentName admin) { List<byte[]> certs = new ArrayList<byte[]>(); - for (String alias : certStore.userAliases()) { + if (mService != null) { try { - certs.add(certStore.getCertificate(alias).getEncoded()); - } catch (CertificateException ce) { - Log.w(TAG, "Could not encode certificate: " + alias, ce); + mService.enforceCanManageCaCerts(admin); + final TrustedCertificateStore certStore = new TrustedCertificateStore(); + for (String alias : certStore.userAliases()) { + try { + certs.add(certStore.getCertificate(alias).getEncoded()); + } catch (CertificateException ce) { + Log.w(TAG, "Could not encode certificate: " + alias, ce); + } + } + } catch (RemoteException re) { + Log.w(TAG, "Failed talking with device policy service", re); } } return certs; @@ -1809,13 +1824,19 @@ public class DevicePolicyManager { /** * Returns whether this certificate is installed as a trusted CA. * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param certBuffer encoded form of the certificate to look up. */ - public boolean hasCaCertInstalled(byte[] certBuffer) { - try { - return getCaCertAlias(certBuffer) != null; - } catch (CertificateException ce) { - Log.w(TAG, "Could not parse certificate", ce); + public boolean hasCaCertInstalled(ComponentName admin, byte[] certBuffer) { + if (mService != null) { + try { + mService.enforceCanManageCaCerts(admin); + return getCaCertAlias(certBuffer) != null; + } catch (RemoteException re) { + Log.w(TAG, "Failed talking with device policy service", re); + } catch (CertificateException ce) { + Log.w(TAG, "Could not parse certificate", ce); + } } return false; } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index c984cf9..57d8b95 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -124,6 +124,7 @@ interface IDevicePolicyManager { boolean installCaCert(in ComponentName admin, in byte[] certBuffer); void uninstallCaCert(in ComponentName admin, in String alias); + void enforceCanManageCaCerts(in ComponentName admin); void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java index ca7022d..89efeb2 100644 --- a/core/java/android/app/job/JobScheduler.java +++ b/core/java/android/app/job/JobScheduler.java @@ -21,14 +21,24 @@ import java.util.List; import android.content.Context; /** - * Class for scheduling various types of jobs with the scheduling framework on the device. + * This is an API for scheduling various types of jobs against the framework that will be executed + * in your application's own process. + * <p> * See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run - * and how to construct them. + * and how to construct them. You will construct these JobInfo objects and pass them to the + * JobScheduler with {@link #schedule(JobInfo)}. When the criteria declared are met, the + * system will execute this job on your application's {@link android.app.job.JobService}. + * You identify which JobService is meant to execute the logic for your job when you create the + * JobInfo with + * {@link android.app.job.JobInfo.Builder#JobInfo.Builder(int,android.content.ComponentName)}. + * </p> + * <p> * The framework will be intelligent about when you receive your callbacks, and attempt to batch * and defer them as much as possible. Typically if you don't specify a deadline on your job, it * can be run at any moment depending on the current state of the JobScheduler's internal queue, * however it might be deferred as long as until the next time the device is connected to a power * source. + * </p> * <p>You do not * instantiate this class directly; instead, retrieve it through * {@link android.content.Context#getSystemService diff --git a/core/java/android/app/usage/ConfigurationStats.java b/core/java/android/app/usage/ConfigurationStats.java new file mode 100644 index 0000000..080216c --- /dev/null +++ b/core/java/android/app/usage/ConfigurationStats.java @@ -0,0 +1,161 @@ +/** + * 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.usage; + +import android.content.res.Configuration; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Represents the usage statistics of a device {@link android.content.res.Configuration} for a + * specific time range. + */ +public final class ConfigurationStats implements Parcelable { + + /** + * {@hide} + */ + public Configuration mConfiguration; + + /** + * {@hide} + */ + public long mBeginTimeStamp; + + /** + * {@hide} + */ + public long mEndTimeStamp; + + /** + * {@hide} + */ + public long mLastTimeActive; + + /** + * {@hide} + */ + public long mTotalTimeActive; + + /** + * {@hide} + */ + public int mActivationCount; + + /** + * {@hide} + */ + public ConfigurationStats() { + } + + public ConfigurationStats(ConfigurationStats stats) { + mConfiguration = stats.mConfiguration; + mBeginTimeStamp = stats.mBeginTimeStamp; + mEndTimeStamp = stats.mEndTimeStamp; + mLastTimeActive = stats.mLastTimeActive; + mTotalTimeActive = stats.mTotalTimeActive; + mActivationCount = stats.mActivationCount; + } + + public Configuration getConfiguration() { + return mConfiguration; + } + + /** + * Get the beginning of the time range this {@link ConfigurationStats} represents, + * measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getFirstTimeStamp() { + return mBeginTimeStamp; + } + + /** + * Get the end of the time range this {@link ConfigurationStats} represents, + * measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getLastTimeStamp() { + return mEndTimeStamp; + } + + /** + * Get the last time this configuration was active, measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getLastTimeActive() { + return mLastTimeActive; + } + + /** + * Get the total time this configuration was active, measured in milliseconds. + */ + public long getTotalTimeActive() { + return mTotalTimeActive; + } + + /** + * Get the number of times this configuration was active. + */ + public int getActivationCount() { + return mActivationCount; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + if (mConfiguration != null) { + dest.writeInt(1); + mConfiguration.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } + + dest.writeLong(mBeginTimeStamp); + dest.writeLong(mEndTimeStamp); + dest.writeLong(mLastTimeActive); + dest.writeLong(mTotalTimeActive); + dest.writeInt(mActivationCount); + } + + public static final Creator<ConfigurationStats> CREATOR = new Creator<ConfigurationStats>() { + @Override + public ConfigurationStats createFromParcel(Parcel source) { + ConfigurationStats stats = new ConfigurationStats(); + if (source.readInt() != 0) { + stats.mConfiguration = Configuration.CREATOR.createFromParcel(source); + } + stats.mBeginTimeStamp = source.readLong(); + stats.mEndTimeStamp = source.readLong(); + stats.mLastTimeActive = source.readLong(); + stats.mTotalTimeActive = source.readLong(); + stats.mActivationCount = source.readInt(); + return stats; + } + + @Override + public ConfigurationStats[] newArray(int size) { + return new ConfigurationStats[size]; + } + }; +} diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 3b09888..4ed1489 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -27,5 +27,7 @@ import android.content.pm.ParceledListSlice; interface IUsageStatsManager { ParceledListSlice queryUsageStats(int bucketType, long beginTime, long endTime, String callingPackage); + ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime, + String callingPackage); UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); } diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index fb80de2..1a947ec 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -16,6 +16,7 @@ package android.app.usage; import android.content.ComponentName; +import android.content.res.Configuration; import android.os.Parcel; import android.os.Parcelable; @@ -63,6 +64,11 @@ public final class UsageEvents implements Parcelable { public static final int CONTINUE_PREVIOUS_DAY = 4; /** + * An event type denoting that the device configuration has changed. + */ + public static final int CONFIGURATION_CHANGE = 5; + + /** * {@hide} */ public String mPackage; @@ -83,6 +89,12 @@ public final class UsageEvents implements Parcelable { public int mEventType; /** + * Only present for {@link #CONFIGURATION_CHANGE} event types. + * {@hide} + */ + public Configuration mConfiguration; + + /** * TODO(adamlesinski): Removed before release. * {@hide} */ @@ -123,6 +135,14 @@ public final class UsageEvents implements Parcelable { public int getEventType() { return mEventType; } + + /** + * Returns a {@link Configuration} for this event if the event is of type + * {@link #CONFIGURATION_CHANGE}, otherwise it returns null. + */ + public Configuration getConfiguration() { + return mConfiguration; + } } // Only used when creating the resulting events. Not used for reading/unparceling. @@ -201,23 +221,9 @@ public final class UsageEvents implements Parcelable { return false; } - final int packageIndex = mParcel.readInt(); - if (packageIndex >= 0) { - eventOut.mPackage = mStringPool[packageIndex]; - } else { - eventOut.mPackage = null; - } + readEventFromParcel(mParcel, eventOut); - final int classIndex = mParcel.readInt(); - if (classIndex >= 0) { - eventOut.mClass = mStringPool[classIndex]; - } else { - eventOut.mClass = null; - } - eventOut.mEventType = mParcel.readInt(); - eventOut.mTimeStamp = mParcel.readLong(); mIndex++; - if (mIndex >= mEventCount) { mParcel.recycle(); mParcel = null; @@ -235,11 +241,6 @@ public final class UsageEvents implements Parcelable { } } - @Override - public int describeContents() { - return 0; - } - private int findStringIndex(String str) { final int index = Arrays.binarySearch(mStringPool, str); if (index < 0) { @@ -248,6 +249,66 @@ public final class UsageEvents implements Parcelable { return index; } + /** + * Writes a single event to the parcel. Modify this when updating {@link Event}. + */ + private void writeEventToParcel(Event event, Parcel p, int flags) { + final int packageIndex; + if (event.mPackage != null) { + packageIndex = findStringIndex(event.mPackage); + } else { + packageIndex = -1; + } + + final int classIndex; + if (event.mClass != null) { + classIndex = findStringIndex(event.mClass); + } else { + classIndex = -1; + } + p.writeInt(packageIndex); + p.writeInt(classIndex); + p.writeInt(event.mEventType); + p.writeLong(event.mTimeStamp); + + if (event.mEventType == Event.CONFIGURATION_CHANGE) { + event.mConfiguration.writeToParcel(p, flags); + } + } + + /** + * Reads a single event from the parcel. Modify this when updating {@link Event}. + */ + private void readEventFromParcel(Parcel p, Event eventOut) { + final int packageIndex = p.readInt(); + if (packageIndex >= 0) { + eventOut.mPackage = mStringPool[packageIndex]; + } else { + eventOut.mPackage = null; + } + + final int classIndex = p.readInt(); + if (classIndex >= 0) { + eventOut.mClass = mStringPool[classIndex]; + } else { + eventOut.mClass = null; + } + eventOut.mEventType = p.readInt(); + eventOut.mTimeStamp = p.readLong(); + + // Extract the configuration for configuration change events. + if (eventOut.mEventType == Event.CONFIGURATION_CHANGE) { + eventOut.mConfiguration = Configuration.CREATOR.createFromParcel(p); + } else { + eventOut.mConfiguration = null; + } + } + + @Override + public int describeContents() { + return 0; + } + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mEventCount); @@ -262,25 +323,9 @@ public final class UsageEvents implements Parcelable { p.setDataPosition(0); for (int i = 0; i < mEventCount; i++) { final Event event = mEventsToWrite.get(i); - - final int packageIndex; - if (event.mPackage != null) { - packageIndex = findStringIndex(event.mPackage); - } else { - packageIndex = -1; - } - - final int classIndex; - if (event.mClass != null) { - classIndex = findStringIndex(event.mClass); - } else { - classIndex = -1; - } - p.writeInt(packageIndex); - p.writeInt(classIndex); - p.writeInt(event.getEventType()); - p.writeLong(event.getTimeStamp()); + writeEventToParcel(event, p, flags); } + final int listByteLength = p.dataPosition(); // Write the total length of the data. diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 5830fcf..bc6099a 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -125,9 +125,9 @@ public final class UsageStatsManager { * @see #INTERVAL_YEARLY * @see #INTERVAL_BEST */ - @SuppressWarnings("unchecked") public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) { try { + @SuppressWarnings("unchecked") ParceledListSlice<UsageStats> slice = mService.queryUsageStats(intervalType, beginTime, endTime, mContext.getOpPackageName()); if (slice != null) { @@ -136,7 +136,32 @@ public final class UsageStatsManager { } catch (RemoteException e) { // fallthrough and return null. } - return Collections.EMPTY_LIST; + return Collections.emptyList(); + } + + /** + * Gets the hardware configurations the device was in for the given time range, aggregated by + * the specified interval. The results are ordered as in + * {@link #queryUsageStats(int, long, long)}. + * + * @param intervalType The time interval by which the stats are aggregated. + * @param beginTime The inclusive beginning of the range of stats to include in the results. + * @param endTime The exclusive end of the range of stats to include in the results. + * @return A list of {@link ConfigurationStats} or null if none are available. + */ + public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime, + long endTime) { + try { + @SuppressWarnings("unchecked") + ParceledListSlice<ConfigurationStats> slice = mService.queryConfigurationStats( + intervalType, beginTime, endTime, mContext.getOpPackageName()); + if (slice != null) { + return slice.getList(); + } + } catch (RemoteException e) { + // fallthrough and return the empty list. + } + return Collections.emptyList(); } /** diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index 119d705..083a48a 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -17,6 +17,7 @@ package android.app.usage; import android.content.ComponentName; +import android.content.res.Configuration; /** * UsageStatsManager local system service interface. @@ -28,14 +29,19 @@ public abstract class UsageStatsManagerInternal { /** * Reports an event to the UsageStatsManager. * - * @param component The component for which this event ocurred. + * @param component The component for which this event occurred. * @param userId The user id to which the component belongs to. - * @param timeStamp The time at which this event ocurred. - * @param eventType The event that occured. Valid values can be found at + * @param eventType The event that occurred. Valid values can be found at * {@link UsageEvents} */ - public abstract void reportEvent(ComponentName component, int userId, - long timeStamp, int eventType); + public abstract void reportEvent(ComponentName component, int userId, int eventType); + + /** + * Reports a configuration change to the UsageStatsManager. + * + * @param config The new device configuration. + */ + public abstract void reportConfigurationChange(Configuration config, int userId); /** * Prepares the UsageStatsService for shutdown. diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index bd45c7e..00248cc 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -188,7 +188,7 @@ public class AppWidgetManager { * this widget. Can have the value {@link * AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or {@link * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD} or {@link - * AppWidgetProviderInfo#WIDGET_CATEGORY_RECENTS}. + * AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}. */ public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory"; diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 02f70c8..b4d79b4 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -61,9 +61,9 @@ public class AppWidgetProviderInfo implements Parcelable { public static final int WIDGET_CATEGORY_KEYGUARD = 2; /** - * Indicates that the widget can be displayed within recents. + * Indicates that the widget can be displayed within a space reserved for the search box. */ - public static final int WIDGET_CATEGORY_RECENTS = 4; + public static final int WIDGET_CATEGORY_SEARCHBOX = 4; /** * Identity of this AppWidget component. This component should be a {@link diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index b98e5ae..36997e5 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -375,6 +375,14 @@ public final class BluetoothSocket implements Closeable { } // else ASSERT(mPort == channel) ret = 0; } catch (IOException e) { + if (mPfd != null) { + try { + mPfd.close(); + } catch (IOException e1) { + Log.e(TAG, "bindListen, close mPfd: " + e1); + } + mPfd = null; + } Log.e(TAG, "bindListen, fail to get port number, exception: " + e); return -1; } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index b825c94..51a58d1 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3363,7 +3363,7 @@ public class Intent implements Parcelable, Cloneable { * profiles - {@link #ACTION_MANAGED_PROFILE_ADDED} and {@link #ACTION_MANAGED_PROFILE_REMOVED}. */ public static final String EXTRA_USER = - "android.intent.extra.user"; + "android.intent.extra.USER"; /** * Extra used in the response from a BroadcastReceiver that handles diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index e63fd07..27bbb24 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -16,6 +16,12 @@ package android.content.res; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import android.content.pm.ActivityInfo; import android.os.Build; import android.os.Parcel; @@ -23,7 +29,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.view.View; -import java.text.Format; +import java.io.IOException; import java.util.ArrayList; import java.util.Locale; @@ -1353,8 +1359,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration * Returns a string representation of the configuration that can be parsed * by build tools (like AAPT). * - * - * * @hide */ public static String resourceQualifierString(Configuration config) { @@ -1568,4 +1572,229 @@ public final class Configuration implements Parcelable, Comparable<Configuration parts.add("v" + Build.VERSION.RESOURCES_SDK_INT); return TextUtils.join("-", parts); } + + /** + * Generate a delta Configuration between <code>base</code> and <code>change</code>. The + * resulting delta can be used with {@link #updateFrom(Configuration)}. + * <p /> + * Caveat: If the any of the Configuration's members becomes undefined, then + * {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member. + * + * This is fine for device configurations as no member is ever undefined. + * {@hide} + */ + public static Configuration generateDelta(Configuration base, Configuration change) { + final Configuration delta = new Configuration(); + if (base.fontScale != change.fontScale) { + delta.fontScale = change.fontScale; + } + + if (base.mcc != change.mcc) { + delta.mcc = change.mcc; + } + + if (base.mnc != change.mnc) { + delta.mnc = change.mnc; + } + + if ((base.locale == null && change.locale != null) || + (base.locale != null && !base.locale.equals(change.locale))) { + delta.locale = change.locale; + } + + if (base.touchscreen != change.touchscreen) { + delta.touchscreen = change.touchscreen; + } + + if (base.keyboard != change.keyboard) { + delta.keyboard = change.keyboard; + } + + if (base.keyboardHidden != change.keyboardHidden) { + delta.keyboardHidden = change.keyboardHidden; + } + + if (base.navigation != change.navigation) { + delta.navigation = change.navigation; + } + + if (base.navigationHidden != change.navigationHidden) { + delta.navigationHidden = change.navigationHidden; + } + + if (base.orientation != change.orientation) { + delta.orientation = change.orientation; + } + + if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) != + (change.screenLayout & SCREENLAYOUT_SIZE_MASK)) { + delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK; + } + + if ((base.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) != + (change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { + delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; + } + + if ((base.screenLayout & SCREENLAYOUT_LONG_MASK) != + (change.screenLayout & SCREENLAYOUT_LONG_MASK)) { + delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK; + } + + if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) { + delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK; + } + + if ((base.uiMode & UI_MODE_NIGHT_MASK) != (change.uiMode & UI_MODE_NIGHT_MASK)) { + delta.uiMode |= change.uiMode & UI_MODE_NIGHT_MASK; + } + + if (base.screenWidthDp != change.screenWidthDp) { + delta.screenWidthDp = change.screenWidthDp; + } + + if (base.screenHeightDp != change.screenHeightDp) { + delta.screenHeightDp = change.screenHeightDp; + } + + if (base.smallestScreenWidthDp != change.smallestScreenWidthDp) { + delta.smallestScreenWidthDp = change.smallestScreenWidthDp; + } + + if (base.densityDpi != change.densityDpi) { + delta.densityDpi = change.densityDpi; + } + return delta; + } + + private static final String XML_ATTR_FONT_SCALE = "fs"; + private static final String XML_ATTR_MCC = "mcc"; + private static final String XML_ATTR_MNC = "mnc"; + private static final String XML_ATTR_LOCALE = "locale"; + private static final String XML_ATTR_TOUCHSCREEN = "touch"; + private static final String XML_ATTR_KEYBOARD = "key"; + private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid"; + private static final String XML_ATTR_HARD_KEYBOARD_HIDDEN = "hardKeyHid"; + private static final String XML_ATTR_NAVIGATION = "nav"; + private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid"; + private static final String XML_ATTR_ORIENTATION = "ori"; + private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay"; + private static final String XML_ATTR_UI_MODE = "ui"; + private static final String XML_ATTR_SCREEN_WIDTH = "width"; + private static final String XML_ATTR_SCREEN_HEIGHT = "height"; + private static final String XML_ATTR_SMALLEST_WIDTH = "sw"; + private static final String XML_ATTR_DENSITY = "density"; + + /** + * Reads the attributes corresponding to Configuration member fields from the Xml parser. + * The parser is expected to be on a tag which has Configuration attributes. + * + * @param parser The Xml parser from which to read attributes. + * @param configOut The Configuration to populate from the Xml attributes. + * {@hide} + */ + public static void readXmlAttrs(XmlPullParser parser, Configuration configOut) + throws XmlPullParserException, IOException { + configOut.fontScale = Float.intBitsToFloat( + XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_SCALE, 0)); + configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0); + configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0); + + final String localeStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALE); + if (localeStr != null) { + configOut.locale = Locale.forLanguageTag(localeStr); + } + + configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN, + TOUCHSCREEN_UNDEFINED); + configOut.keyboard = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD, + KEYBOARD_UNDEFINED); + configOut.keyboardHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD_HIDDEN, + KEYBOARDHIDDEN_UNDEFINED); + configOut.hardKeyboardHidden = + XmlUtils.readIntAttribute(parser, XML_ATTR_HARD_KEYBOARD_HIDDEN, + HARDKEYBOARDHIDDEN_UNDEFINED); + configOut.navigation = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION, + NAVIGATION_UNDEFINED); + configOut.navigationHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION_HIDDEN, + NAVIGATIONHIDDEN_UNDEFINED); + configOut.orientation = XmlUtils.readIntAttribute(parser, XML_ATTR_ORIENTATION, + ORIENTATION_UNDEFINED); + configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT, + SCREENLAYOUT_UNDEFINED); + configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0); + configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH, + SCREEN_WIDTH_DP_UNDEFINED); + configOut.screenHeightDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_HEIGHT, + SCREEN_HEIGHT_DP_UNDEFINED); + configOut.smallestScreenWidthDp = + XmlUtils.readIntAttribute(parser, XML_ATTR_SMALLEST_WIDTH, + SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); + configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY, + DENSITY_DPI_UNDEFINED); + } + + + /** + * Writes the Configuration's member fields as attributes into the XmlSerializer. + * The serializer is expected to have already started a tag so that attributes can be + * immediately written. + * + * @param xml The serializer to which to write the attributes. + * @param config The Configuration whose member fields to write. + * {@hide} + */ + public static void writeXmlAttrs(XmlSerializer xml, Configuration config) throws IOException { + XmlUtils.writeIntAttribute(xml, XML_ATTR_FONT_SCALE, + Float.floatToIntBits(config.fontScale)); + if (config.mcc != 0) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_MCC, config.mcc); + } + if (config.mnc != 0) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc); + } + if (config.locale != null) { + XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALE, config.locale.toLanguageTag()); + } + if (config.touchscreen != TOUCHSCREEN_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen); + } + if (config.keyboard != KEYBOARD_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_KEYBOARD, config.keyboard); + } + if (config.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_KEYBOARD_HIDDEN, config.keyboardHidden); + } + if (config.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_HARD_KEYBOARD_HIDDEN, + config.hardKeyboardHidden); + } + if (config.navigation != NAVIGATION_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_NAVIGATION, config.navigation); + } + if (config.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_NAVIGATION_HIDDEN, config.navigationHidden); + } + if (config.orientation != ORIENTATION_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_ORIENTATION, config.orientation); + } + if (config.screenLayout != SCREENLAYOUT_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_LAYOUT, config.screenLayout); + } + if (config.uiMode != 0) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_UI_MODE, config.uiMode); + } + if (config.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_WIDTH, config.screenWidthDp); + } + if (config.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_HEIGHT, config.screenHeightDp); + } + if (config.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_SMALLEST_WIDTH, config.smallestScreenWidthDp); + } + if (config.densityDpi != DENSITY_DPI_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_DENSITY, config.densityDpi); + } + } } diff --git a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java index d0a3a3f..d5ec71a 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java @@ -114,21 +114,24 @@ public class LegacyFocusStateMapper { currentAfRun = mAfRun; } - mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() { + Camera.AutoFocusMoveCallback afMoveCallback = new Camera.AutoFocusMoveCallback() { @Override public void onAutoFocusMoving(boolean start, Camera camera) { synchronized (mLock) { int latestAfRun = mAfRun; if (VERBOSE) { - Log.v(TAG, "onAutoFocusMoving - start " + start + " latest AF run " + - latestAfRun + ", last AF run " + currentAfRun); + Log.v(TAG, + "onAutoFocusMoving - start " + start + " latest AF run " + + latestAfRun + ", last AF run " + currentAfRun + ); } if (currentAfRun != latestAfRun) { Log.d(TAG, "onAutoFocusMoving - ignoring move callbacks from old af run" - + currentAfRun); + + currentAfRun + ); return; } @@ -151,9 +154,19 @@ public class LegacyFocusStateMapper { mAfState = newAfState; } } - }); + }; + + // Only set move callback if we can call autofocus. + switch (afMode) { + case Parameters.FOCUS_MODE_AUTO: + case Parameters.FOCUS_MODE_MACRO: + case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE: + case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO: + mCamera.setAutoFocusMoveCallback(afMoveCallback); + } } + // AF Locking switch (afTrigger) { case CONTROL_AF_TRIGGER_START: @@ -167,6 +180,7 @@ public class LegacyFocusStateMapper { case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE: case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO: afStateAfterStart = CONTROL_AF_STATE_PASSIVE_SCAN; + break; default: // EDOF, INFINITY afStateAfterStart = CONTROL_AF_STATE_INACTIVE; @@ -183,6 +197,11 @@ public class LegacyFocusStateMapper { "new AF run is " + currentAfRun); } + // Avoid calling autofocus unless we are in a state that supports calling this. + if (afStateAfterStart == CONTROL_AF_STATE_INACTIVE) { + break; + } + mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java index 4c4ad0d..42ee4fa 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java @@ -122,7 +122,10 @@ public class LegacyRequestMapper { activeArray, zoomData, aeRegions, maxNumMeteringAreas, /*regionName*/"AE"); - params.setMeteringAreas(meteringAreaList); + // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null). + if (maxNumMeteringAreas > 0) { + params.setMeteringAreas(meteringAreaList); + } } // afRegions @@ -133,7 +136,10 @@ public class LegacyRequestMapper { activeArray, zoomData, afRegions, maxNumFocusAreas, /*regionName*/"AF"); - params.setFocusAreas(focusAreaList); + // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null). + if (maxNumFocusAreas > 0) { + params.setFocusAreas(focusAreaList); + } } } diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index 4b5ced9..30f3576 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -55,10 +55,29 @@ public final class HdmiControlManager { public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1; /** + * Message used by TV to receive volume status from Audio Receiver. It should check volume value + * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRAM_PARAM1}. If the + * value is in range of [0,100], it is current volume of Audio Receiver. And there is another + * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute. + */ + public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2; + + /** * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the ID of * the message to display on screen. */ public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID"; + /** + * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value + * of the message. + */ + public static final String EXTRA_MESSAGE_EXTRAM_PARAM1 = + "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1"; + + /** + * Volume value for mute state. + */ + public static final int AVR_VOLUME_MUTED = 101; public static final int POWER_STATUS_UNKNOWN = -1; public static final int POWER_STATUS_ON = 0; diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4bfef41..70b402d 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -685,6 +685,23 @@ public class ConnectivityManager { } /** + * Returns the {@link Network} object currently serving a given type, or + * null if the given type is not connected. + * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * + * @hide + */ + public Network getNetworkForType(int networkType) { + try { + return mService.getNetworkForType(networkType); + } catch (RemoteException e) { + return null; + } + } + + /** * Returns an array of all {@link Network} currently tracked by the * framework. * @@ -1281,7 +1298,7 @@ public class ConnectivityManager { } /** - * Callback for use with {@link ConnectivityManager#registerDefaultNetworkActiveListener} + * Callback for use with {@link ConnectivityManager#addDefaultNetworkActiveListener} * to find out when the system default network has gone in to a high power state. */ public interface OnNetworkActiveListener { @@ -1323,7 +1340,7 @@ public class ConnectivityManager { * * @param l The listener to be told when the network is active. */ - public void registerDefaultNetworkActiveListener(final OnNetworkActiveListener l) { + public void addDefaultNetworkActiveListener(final OnNetworkActiveListener l) { INetworkActivityListener rl = new INetworkActivityListener.Stub() { @Override public void onNetworkActive() throws RemoteException { @@ -1340,11 +1357,11 @@ public class ConnectivityManager { /** * Remove network active listener previously registered with - * {@link #registerDefaultNetworkActiveListener}. + * {@link #addDefaultNetworkActiveListener}. * * @param l Previously registered listener. */ - public void unregisterDefaultNetworkActiveListener(OnNetworkActiveListener l) { + public void removeDefaultNetworkActiveListener(OnNetworkActiveListener l) { INetworkActivityListener rl = mNetworkActivityListeners.get(l); if (rl == null) { throw new IllegalArgumentException("Listener not registered: " + l); diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b2fc3be..974c4cd 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -48,6 +48,7 @@ interface IConnectivityManager NetworkInfo getNetworkInfo(int networkType); NetworkInfo getNetworkInfoForNetwork(in Network network); NetworkInfo[] getAllNetworkInfo(); + Network getNetworkForType(int networkType); Network[] getAllNetworks(); NetworkInfo getProvisioningOrActiveNetworkInfo(); diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index f9a25f9..c387055 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -274,7 +274,6 @@ public class LinkAddress implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public int describeContents() { return 0; @@ -282,7 +281,6 @@ public class LinkAddress implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public void writeToParcel(Parcel dest, int flags) { dest.writeByteArray(address.getAddress()); @@ -293,7 +291,6 @@ public class LinkAddress implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public static final Creator<LinkAddress> CREATOR = new Creator<LinkAddress>() { diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index d2a4728..e686be7 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -35,6 +35,7 @@ import java.net.URLStreamHandler; import java.util.concurrent.atomic.AtomicReference; import javax.net.SocketFactory; +import com.android.okhttp.ConnectionPool; import com.android.okhttp.HostResolver; import com.android.okhttp.OkHttpClient; @@ -60,6 +61,17 @@ public class Network implements Parcelable { private volatile OkHttpClient mOkHttpClient = null; private Object mLock = new Object(); + // Default connection pool values. These are evaluated at startup, just + // like the OkHttp code. Also like the OkHttp code, we will throw parse + // exceptions at class loading time if the properties are set but are not + // valid integers. + private static final boolean httpKeepAlive = + Boolean.parseBoolean(System.getProperty("http.keepAlive", "true")); + private static final int httpMaxConnections = + httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0; + private static final long httpKeepAliveDurationMs = + Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes. + /** * @hide */ @@ -183,6 +195,20 @@ public class Network implements Parcelable { return mNetworkBoundSocketFactory; } + // TODO: This creates an OkHttpClient with its own connection pool for + // every Network object, instead of one for every NetId. This is + // suboptimal, because an app could potentially have more than one + // Network object for the same NetId, causing increased memory footprint + // and performance penalties due to lack of connection reuse (connection + // setup time, congestion window growth time, etc.). + // + // Instead, investigate only having one OkHttpClient for every NetId, + // perhaps by using a static HashMap of NetIds to OkHttpClient objects. The + // tricky part is deciding when to remove an OkHttpClient; a WeakHashMap + // shouldn't be used because whether a Network is referenced doesn't + // correlate with whether a new Network will be instantiated in the near + // future with the same NetID. A good solution would involve purging empty + // (or when all connections are timed out) ConnectionPools. private void maybeInitHttpClient() { if (mOkHttpClient == null) { synchronized (mLock) { @@ -193,9 +219,12 @@ public class Network implements Parcelable { return Network.this.getAllByName(host); } }; + ConnectionPool pool = new ConnectionPool(httpMaxConnections, + httpKeepAliveDurationMs); mOkHttpClient = new OkHttpClient() .setSocketFactory(getSocketFactory()) - .setHostResolver(hostResolver); + .setHostResolver(hostResolver) + .setConnectionPool(pool); } } } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index d279412..7664c95 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -128,14 +128,6 @@ public class NetworkInfo implements Parcelable { private boolean mIsAvailable; /** - * @param type network type - * @deprecated - * @hide because this constructor was only meant for internal use (and - * has now been superseded by the package-private constructor below). - */ - public NetworkInfo(int type) {} - - /** * @hide */ public NetworkInfo(int type, int subtype, String typeName, String subtypeName) { diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 83bdfaa..5a09b46 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -52,6 +52,9 @@ public class NetworkRequest implements Parcelable { * @hide */ public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId) { + if (nc == null) { + throw new NullPointerException(); + } requestId = rId; networkCapabilities = nc; this.legacyType = legacyType; diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 7ea6bae..1534e2c 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -334,10 +334,6 @@ public class ProxyInfo implements Parcelable { dest.writeStringArray(mParsedExclusionList); } - /** - * Implement the Parcelable interface. - * @hide - */ public static final Creator<ProxyInfo> CREATOR = new Creator<ProxyInfo>() { public ProxyInfo createFromParcel(Parcel in) { diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index b0e0b49..1e0dc53 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -541,7 +541,7 @@ public class Build { * Intent.</li> * </ul> */ - public static final int L = CUR_DEVELOPMENT; + public static final int L = 21; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 6d4a302..b3e28ea 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -19,6 +19,7 @@ package android.os; import android.net.InterfaceConfiguration; import android.net.INetworkManagementEventObserver; +import android.net.Network; import android.net.NetworkStats; import android.net.RouteInfo; import android.net.UidRange; @@ -164,10 +165,10 @@ interface INetworkManagementService /** * Sets the list of DNS forwarders (in order of priority) */ - void setDnsForwarders(in String[] dns); + void setDnsForwarders(in Network network, in String[] dns); /** - * Returns the list of DNS fowarders (in order of priority) + * Returns the list of DNS forwarders (in order of priority) */ String[] getDnsForwarders(); diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 5ce9d5c..0ff5f6a 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -234,6 +234,7 @@ public final class UserHandle implements Parcelable { * @return user id of the current process * @hide */ + @SystemApi public static final int myUserId() { return getUserId(Process.myUid()); } @@ -253,7 +254,11 @@ public final class UserHandle implements Parcelable { mHandle = h; } - /** @hide */ + /** + * Returns the userId stored in this UserHandle. + * @hide + */ + @SystemApi public int getIdentifier() { return mHandle; } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index f793667..3749892 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -15,6 +15,7 @@ */ package android.os; +import android.annotation.SystemApi; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.content.Context; @@ -424,6 +425,19 @@ public class UserManager { } /** + * Checks if the calling app is running in a managed profile. + * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * + * @return whether the caller is in a managed profile. + * @hide + */ + @SystemApi + public boolean isManagedProfile() { + UserInfo user = getUserInfo(UserHandle.myUserId()); + return user != null ? user.isManagedProfile() : false; + } + + /** * Return whether the given user is actively running. This means that * the user is in the "started" state, not "stopped" -- it is currently * allowed to run code through scheduled alarms, receiving broadcasts, @@ -646,6 +660,7 @@ public class UserManager { try { Bundle guestRestrictions = mService.getDefaultGuestRestrictions(); guestRestrictions.putBoolean(DISALLOW_SMS, true); + guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true); mService.setUserRestrictions(guestRestrictions, guest.id); } catch (RemoteException re) { Log.w(TAG, "Could not update guest restrictions"); diff --git a/core/java/android/preference/CheckBoxPreference.java b/core/java/android/preference/CheckBoxPreference.java index 1ce98b8..fee3f0f 100644 --- a/core/java/android/preference/CheckBoxPreference.java +++ b/core/java/android/preference/CheckBoxPreference.java @@ -66,7 +66,6 @@ public class CheckBoxPreference extends TwoStatePreference { View checkboxView = view.findViewById(com.android.internal.R.id.checkbox); if (checkboxView != null && checkboxView instanceof Checkable) { ((Checkable) checkboxView).setChecked(mChecked); - sendAccessibilityEvent(checkboxView); } syncSummaryView(view); diff --git a/core/java/android/preference/SwitchPreference.java b/core/java/android/preference/SwitchPreference.java index 46be928..53b5aad 100644 --- a/core/java/android/preference/SwitchPreference.java +++ b/core/java/android/preference/SwitchPreference.java @@ -130,8 +130,6 @@ public class SwitchPreference extends TwoStatePreference { ((Checkable) checkableView).setChecked(mChecked); - sendAccessibilityEvent(checkableView); - if (checkableView instanceof Switch) { final Switch switchView = (Switch) checkableView; switchView.setTextOn(mSwitchOn); diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java index 6f8be1f..3823b27 100644 --- a/core/java/android/preference/TwoStatePreference.java +++ b/core/java/android/preference/TwoStatePreference.java @@ -24,8 +24,6 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; import android.widget.TextView; /** @@ -39,7 +37,6 @@ public abstract class TwoStatePreference extends Preference { private CharSequence mSummaryOff; boolean mChecked; private boolean mCheckedSet; - private boolean mSendClickAccessibilityEvent; private boolean mDisableDependentsState; public TwoStatePreference( @@ -63,15 +60,10 @@ public abstract class TwoStatePreference extends Preference { protected void onClick() { super.onClick(); - boolean newValue = !isChecked(); - - mSendClickAccessibilityEvent = true; - - if (!callChangeListener(newValue)) { - return; + final boolean newValue = !isChecked(); + if (callChangeListener(newValue)) { + setChecked(newValue); } - - setChecked(newValue); } /** @@ -196,21 +188,6 @@ public abstract class TwoStatePreference extends Preference { : (Boolean) defaultValue); } - void sendAccessibilityEvent(View view) { - // Since the view is still not attached we create, populate, - // and send the event directly since we do not know when it - // will be attached and posting commands is not as clean. - AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getContext()); - if (mSendClickAccessibilityEvent && accessibilityManager.isEnabled()) { - AccessibilityEvent event = AccessibilityEvent.obtain(); - event.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED); - view.onInitializeAccessibilityEvent(event); - view.dispatchPopulateAccessibilityEvent(event); - accessibilityManager.sendAccessibilityEvent(event); - } - mSendClickAccessibilityEvent = false; - } - /** * Sync a summary view contained within view's subhierarchy with the correct summary text. * @param view View where a summary should be located diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 0202f91..5fa1cc9 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -116,8 +116,8 @@ public class CallLog { * </pre> * </p> */ - public static final String EXTRA_CALL_TYPE_FILTER - = "android.provider.extra.call_type_filter"; + public static final String EXTRA_CALL_TYPE_FILTER = + "android.provider.extra.CALL_TYPE_FILTER"; /** * Content uri used to access call log entries, including voicemail records. You must have diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 27473e3..18a9eb1 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1125,7 +1125,7 @@ public final class ContactsContract { * import android.provider.ContactsContract.Contacts; * * Uri uri = Contacts.CONTENT_URI.buildUpon() - * .appendQueryParameter(Contacts.ADDRESS_BOOK_INDEX_EXTRAS, "true") + * .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true") * .build(); * Cursor cursor = getContentResolver().query(uri, * new String[] {Contacts.DISPLAY_NAME}, @@ -1140,21 +1140,24 @@ public final class ContactsContract { * </pre> * </p> */ - public static final String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; + public static final String EXTRA_ADDRESS_BOOK_INDEX = + "android.provider.extra.ADDRESS_BOOK_INDEX"; /** * The array of address book index titles, which are returned in the * same order as the data in the cursor. * <p>TYPE: String[]</p> */ - public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = + "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; /** * The array of group counts for the corresponding group. Contains the same number * of elements as the EXTRA_ADDRESS_BOOK_INDEX_TITLES array. * <p>TYPE: int[]</p> */ - public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; + public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = + "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; } /** @@ -8111,7 +8114,7 @@ public final class ContactsContract { * for the provided {@link Contacts} entry. */ public static final String ACTION_QUICK_CONTACT = - "com.android.contacts.action.QUICK_CONTACT"; + "android.provider.action.QUICK_CONTACT"; /** * Extra used to specify pivot dialog location in screen coordinates. diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index cb0bcf2..2ca8098 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -26,6 +26,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; +import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -101,6 +102,7 @@ public abstract class NotificationListenerService extends Service { * <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li> * <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li> * <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li> + * <li>{@link Notification#EXTRA_BIG_TEXT extras[EXTRA_BIG_TEXT]}</li> * </ol> * * @hide @@ -692,10 +694,15 @@ public abstract class NotificationListenerService extends Service { * current {@link RankingMap}. */ public static class Ranking { + /** Value signifying that the user has not expressed a per-app visibility override value. + * @hide */ + public static final int VISIBILITY_NO_OVERRIDE = -1000; + private String mKey; private int mRank = -1; private boolean mIsAmbient; private boolean mMatchesInterruptionFilter; + private int mVisibilityOverride; public Ranking() {} @@ -725,6 +732,17 @@ public abstract class NotificationListenerService extends Service { } /** + * Returns the user specificed visibility for the package that posted + * this notification, or + * {@link NotificationListenerService.Ranking#VISIBILITY_NO_OVERRIDE} if + * no such preference has been expressed. + * @hide + */ + public int getVisibilityOverride() { + return mVisibilityOverride; + } + + /** * Returns whether the notification meets the user's interruption * filter. * @@ -743,11 +761,12 @@ public abstract class NotificationListenerService extends Service { } private void populate(String key, int rank, boolean isAmbient, - boolean matchesInterruptionFilter) { + boolean matchesInterruptionFilter, int visibilityOverride) { mKey = key; mRank = rank; mIsAmbient = isAmbient; mMatchesInterruptionFilter = matchesInterruptionFilter; + mVisibilityOverride = visibilityOverride; } } @@ -763,6 +782,7 @@ public abstract class NotificationListenerService extends Service { private final NotificationRankingUpdate mRankingUpdate; private ArrayMap<String,Integer> mRanks; private ArraySet<Object> mIntercepted; + private ArrayMap<String, Integer> mVisibilityOverrides; private RankingMap(NotificationRankingUpdate rankingUpdate) { mRankingUpdate = rankingUpdate; @@ -787,7 +807,8 @@ public abstract class NotificationListenerService extends Service { */ public boolean getRanking(String key, Ranking outRanking) { int rank = getRank(key); - outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key)); + outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key), + getVisibilityOverride(key)); return rank >= 0; } @@ -819,6 +840,19 @@ public abstract class NotificationListenerService extends Service { return mIntercepted.contains(key); } + private int getVisibilityOverride(String key) { + synchronized (this) { + if (mVisibilityOverrides == null) { + buildVisibilityOverridesLocked(); + } + } + Integer overide = mVisibilityOverrides.get(key); + if (overide == null) { + return Ranking.VISIBILITY_NO_OVERRIDE; + } + return overide.intValue(); + } + // Locked by 'this' private void buildRanksLocked() { String[] orderedKeys = mRankingUpdate.getOrderedKeys(); @@ -836,6 +870,15 @@ public abstract class NotificationListenerService extends Service { Collections.addAll(mIntercepted, dndInterceptedKeys); } + // Locked by 'this' + private void buildVisibilityOverridesLocked() { + Bundle visibilityBundle = mRankingUpdate.getVisibilityOverrides(); + mVisibilityOverrides = new ArrayMap<>(visibilityBundle.size()); + for (String key: visibilityBundle.keySet()) { + mVisibilityOverrides.put(key, visibilityBundle.getInt(key)); + } + } + // ----------- Parcelable @Override diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java index 26af38b..6fba900 100644 --- a/core/java/android/service/notification/NotificationRankingUpdate.java +++ b/core/java/android/service/notification/NotificationRankingUpdate.java @@ -15,6 +15,7 @@ */ package android.service.notification; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -26,18 +27,21 @@ public class NotificationRankingUpdate implements Parcelable { private final String[] mKeys; private final String[] mInterceptedKeys; private final int mFirstAmbientIndex; + private final Bundle mVisibilityOverrides; public NotificationRankingUpdate(String[] keys, String[] interceptedKeys, - int firstAmbientIndex) { + Bundle visibilityOverrides, int firstAmbientIndex) { mKeys = keys; mFirstAmbientIndex = firstAmbientIndex; mInterceptedKeys = interceptedKeys; + mVisibilityOverrides = visibilityOverrides; } public NotificationRankingUpdate(Parcel in) { mKeys = in.readStringArray(); mFirstAmbientIndex = in.readInt(); mInterceptedKeys = in.readStringArray(); + mVisibilityOverrides = in.readBundle(); } @Override @@ -50,6 +54,7 @@ public class NotificationRankingUpdate implements Parcelable { out.writeStringArray(mKeys); out.writeInt(mFirstAmbientIndex); out.writeStringArray(mInterceptedKeys); + out.writeBundle(mVisibilityOverrides); } public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR @@ -74,4 +79,8 @@ public class NotificationRankingUpdate implements Parcelable { public String[] getInterceptedKeys() { return mInterceptedKeys; } + + public Bundle getVisibilityOverrides() { + return mVisibilityOverrides; + } } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 519bc28..4de5f41 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -450,7 +450,7 @@ public class AlwaysOnHotwordDetector { * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}. * Starting re-enrollment is only valid if the keyphrase is un-enrolled, * i.e. {@link #STATE_KEYPHRASE_UNENROLLED}, - * otherwise {@link #createIntentToReEnroll()} should be preferred. + * otherwise {@link #createReEnrollIntent()} should be preferred. * * @return An {@link Intent} to start enrollment for the given keyphrase. * @throws UnsupportedOperationException if managing they keyphrase isn't supported. @@ -460,6 +460,19 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ + public Intent createEnrollIntent() { + if (DBG) Slog.d(TAG, "createEnrollIntent"); + synchronized (mLock) { + return getManageIntentLocked(MANAGE_ACTION_ENROLL); + } + } + + /** + * FIXME: Remove once the prebuilts are updated. + * + * @hide + */ + @Deprecated public Intent createIntentToEnroll() { if (DBG) Slog.d(TAG, "createIntentToEnroll"); synchronized (mLock) { @@ -481,6 +494,19 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ + public Intent createUnEnrollIntent() { + if (DBG) Slog.d(TAG, "createUnEnrollIntent"); + synchronized (mLock) { + return getManageIntentLocked(MANAGE_ACTION_UN_ENROLL); + } + } + + /** + * FIXME: Remove once the prebuilts are updated. + * + * @hide + */ + @Deprecated public Intent createIntentToUnEnroll() { if (DBG) Slog.d(TAG, "createIntentToUnEnroll"); synchronized (mLock) { @@ -502,6 +528,19 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ + public Intent createReEnrollIntent() { + if (DBG) Slog.d(TAG, "createReEnrollIntent"); + synchronized (mLock) { + return getManageIntentLocked(MANAGE_ACTION_RE_ENROLL); + } + } + + /** + * FIXME: Remove once the prebuilts are updated. + * + * @hide + */ + @Deprecated public Intent createIntentToReEnroll() { if (DBG) Slog.d(TAG, "createIntentToReEnroll"); synchronized (mLock) { diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 7dce348..2b53c48 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -727,10 +727,9 @@ public abstract class Layout { int[] runs = dirs.mDirections; int lineStart = getLineStart(line); for (int i = 0; i < runs.length; i += 2) { - int start = lineStart + (runs[i] & RUN_LENGTH_MASK); - // No need to test the end as an offset after the last run should return the value - // corresponding of the last run - if (offset >= start) { + int start = lineStart + runs[i]; + int limit = start + (runs[i+1] & RUN_LENGTH_MASK); + if (offset >= start && offset < limit) { int level = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK; return ((level & 1) != 0); } diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java index 679e2cc..3222dbf 100644 --- a/core/java/android/text/Selection.java +++ b/core/java/android/text/Selection.java @@ -116,7 +116,8 @@ public class Selection { /** * Move the cursor to the buffer offset physically above the current - * offset, or return false if the cursor is already on the top line. + * offset, to the beginning if it is on the top line but not at the + * start, or return false if the cursor is already on the top line. */ public static boolean moveUp(Spannable text, Layout layout) { int start = getSelectionStart(text); @@ -149,6 +150,9 @@ public class Selection { setSelection(text, move); return true; + } else if (end != 0) { + setSelection(text, 0); + return true; } } @@ -157,7 +161,9 @@ public class Selection { /** * Move the cursor to the buffer offset physically below the current - * offset, or return false if the cursor is already on the bottom line. + * offset, to the end of the buffer if it is on the bottom line but + * not at the end, or return false if the cursor is already at the + * end of the buffer. */ public static boolean moveDown(Spannable text, Layout layout) { int start = getSelectionStart(text); @@ -190,6 +196,9 @@ public class Selection { setSelection(text, move); return true; + } else if (end != text.length()) { + setSelection(text, text.length()); + return true; } } diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java index d579f54..cb0a875 100644 --- a/core/java/android/transition/ChangeTransform.java +++ b/core/java/android/transition/ChangeTransform.java @@ -45,6 +45,10 @@ public class ChangeTransform extends Transition { private static final String PROPNAME_TRANSFORMS = "android:changeTransform:transforms"; private static final String PROPNAME_PARENT = "android:changeTransform:parent"; private static final String PROPNAME_PARENT_MATRIX = "android:changeTransform:parentMatrix"; + private static final String PROPNAME_INTERMEDIATE_PARENT_MATRIX = + "android:changeTransform:intermediateParentMatrix"; + private static final String PROPNAME_INTERMEDIATE_MATRIX = + "android:changeTransform:intermediateMatrix"; private static final String[] sTransitionProperties = { PROPNAME_MATRIX, @@ -172,6 +176,10 @@ public class ChangeTransform extends Transition { parent.transformMatrixToGlobal(parentMatrix); parentMatrix.preTranslate(-parent.getScrollX(), -parent.getScrollY()); transitionValues.values.put(PROPNAME_PARENT_MATRIX, parentMatrix); + transitionValues.values.put(PROPNAME_INTERMEDIATE_MATRIX, + view.getTag(R.id.transitionTransform)); + transitionValues.values.put(PROPNAME_INTERMEDIATE_PARENT_MATRIX, + view.getTag(R.id.parentMatrix)); } return; } @@ -199,12 +207,13 @@ public class ChangeTransform extends Transition { ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT); boolean handleParentChange = mReparent && !parentsMatch(startParent, endParent); - Matrix startMatrix = (Matrix) startValues.view.getTag(R.id.transitionTransform); + Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_INTERMEDIATE_MATRIX); if (startMatrix != null) { startValues.values.put(PROPNAME_MATRIX, startMatrix); } - Matrix startParentMatrix = (Matrix) startValues.view.getTag(R.id.parentMatrix); + Matrix startParentMatrix = (Matrix) + startValues.values.get(PROPNAME_INTERMEDIATE_PARENT_MATRIX); if (startParentMatrix != null) { startValues.values.put(PROPNAME_PARENT_MATRIX, startParentMatrix); } @@ -250,9 +259,11 @@ public class ChangeTransform extends Transition { ObjectAnimator animator = ObjectAnimator.ofObject(view, ANIMATION_MATRIX_PROPERTY, new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix); + final Matrix finalEndMatrix = endMatrix; + AnimatorListenerAdapter listener = new AnimatorListenerAdapter() { private boolean mIsCanceled; - private Matrix mTempMatrix; + private Matrix mTempMatrix = new Matrix(); @Override public void onAnimationCancel(Animator animation) { @@ -262,8 +273,7 @@ public class ChangeTransform extends Transition { @Override public void onAnimationEnd(Animator animation) { if (!mIsCanceled) { - view.setTagInternal(R.id.transitionTransform, null); - view.setTagInternal(R.id.parentMatrix, null); + setCurrentMatrix(finalEndMatrix); } ANIMATION_MATRIX_PROPERTY.set(view, null); transforms.restore(view); @@ -273,19 +283,19 @@ public class ChangeTransform extends Transition { public void onAnimationPause(Animator animation) { ValueAnimator animator = (ValueAnimator) animation; Matrix currentMatrix = (Matrix) animator.getAnimatedValue(); - if (mTempMatrix == null) { - mTempMatrix = new Matrix(currentMatrix); - } else { - mTempMatrix.set(currentMatrix); - } - view.setTagInternal(R.id.transitionTransform, mTempMatrix); - transforms.restore(view); + setCurrentMatrix(currentMatrix); } @Override public void onAnimationResume(Animator animation) { setIdentityTransforms(view); } + + private void setCurrentMatrix(Matrix currentMatrix) { + mTempMatrix.set(currentMatrix); + view.setTagInternal(R.id.transitionTransform, mTempMatrix); + transforms.restore(view); + } }; animator.addListener(listener); @@ -423,6 +433,8 @@ public class ChangeTransform extends Transition { public void onTransitionEnd(Transition transition) { transition.removeListener(this); GhostView.removeGhost(mView); + mView.setTagInternal(R.id.transitionTransform, null); + mView.setTagInternal(R.id.parentMatrix, null); } @Override diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index ce3cc2f..7bd6287 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -182,11 +182,15 @@ public class TransitionManager { final ViewGroup sceneRoot = scene.getSceneRoot(); - Transition transitionClone = transition.clone(); - transitionClone.setSceneRoot(sceneRoot); + Transition transitionClone = null; + if (transition != null) { + transitionClone = transition.clone(); + transitionClone.setSceneRoot(sceneRoot); + } Scene oldScene = Scene.getCurrentScene(sceneRoot); - if (oldScene != null && oldScene.isCreatedFromLayoutResource()) { + if (oldScene != null && transitionClone != null && + oldScene.isCreatedFromLayoutResource()) { transitionClone.setCanRemoveViews(true); } diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java index b0c9e9a..a84ecd1 100644 --- a/core/java/android/transition/TransitionUtils.java +++ b/core/java/android/transition/TransitionUtils.java @@ -40,6 +40,33 @@ public class TransitionUtils { } } + public static Transition mergeTransitions(Transition... transitions) { + int count = 0; + int nonNullIndex = -1; + for (int i = 0; i < transitions.length; i++) { + if (transitions[i] != null) { + count++; + nonNullIndex = i; + } + } + + if (count == 0) { + return null; + } + + if (count == 1) { + return transitions[nonNullIndex]; + } + + TransitionSet transitionSet = new TransitionSet(); + for (int i = 0; i < transitions.length; i++) { + if (transitions[i] != null) { + transitionSet.addTransition(transitions[i]); + } + } + return transitionSet; + } + public static class MatrixEvaluator implements TypeEvaluator<Matrix> { float[] mTempStartValues = new float[9]; diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 477c994..a10dda3 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -18,6 +18,7 @@ package android.view; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.Region; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -96,7 +97,7 @@ final class AccessibilityInteractionController { } public void findAccessibilityNodeInfoByAccessibilityIdClientThread( - long accessibilityNodeId, int interactionId, + long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); @@ -109,6 +110,7 @@ final class AccessibilityInteractionController { args.argi3 = interactionId; args.arg1 = callback; args.arg2 = spec; + args.arg3 = interactiveRegion; message.obj = args; // If the interrogation is performed by the same thread as the main UI @@ -133,6 +135,7 @@ final class AccessibilityInteractionController { final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; final MagnificationSpec spec = (MagnificationSpec) args.arg2; + final Region interactiveRegion = (Region) args.arg3; args.recycle(); @@ -159,6 +162,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); infos.clear(); } catch (RemoteException re) { @@ -168,8 +172,9 @@ final class AccessibilityInteractionController { } public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId, - String viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, - int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { + String viewId, Region interactiveRegion, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, + long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID; message.arg1 = flags; @@ -180,6 +185,7 @@ final class AccessibilityInteractionController { args.arg1 = callback; args.arg2 = spec; args.arg3 = viewId; + args.arg4 = interactiveRegion; message.obj = args; @@ -205,6 +211,7 @@ final class AccessibilityInteractionController { (IAccessibilityInteractionConnectionCallback) args.arg1; final MagnificationSpec spec = (MagnificationSpec) args.arg2; final String viewId = (String) args.arg3; + final Region interactiveRegion = (Region) args.arg4; args.recycle(); @@ -241,6 +248,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -249,8 +257,9 @@ final class AccessibilityInteractionController { } public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId, - String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, - int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { + String text, Region interactiveRegion, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, + long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT; message.arg1 = flags; @@ -262,6 +271,7 @@ final class AccessibilityInteractionController { args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); args.argi3 = interactionId; + args.arg4 = interactiveRegion; message.obj = args; // If the interrogation is performed by the same thread as the main UI @@ -287,6 +297,7 @@ final class AccessibilityInteractionController { final int accessibilityViewId = args.argi1; final int virtualDescendantId = args.argi2; final int interactionId = args.argi3; + final Region interactiveRegion = (Region) args.arg4; args.recycle(); List<AccessibilityNodeInfo> infos = null; @@ -347,6 +358,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -354,7 +366,8 @@ final class AccessibilityInteractionController { } } - public void findFocusClientThread(long accessibilityNodeId, int focusType, int interactionId, + public void findFocusClientThread(long accessibilityNodeId, int focusType, + Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid, long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); @@ -368,6 +381,7 @@ final class AccessibilityInteractionController { args.argi3 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); args.arg1 = callback; args.arg2 = spec; + args.arg3 = interactiveRegion; message.obj = args; @@ -394,6 +408,7 @@ final class AccessibilityInteractionController { final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; final MagnificationSpec spec = (MagnificationSpec) args.arg2; + final Region interactiveRegion = (Region) args.arg3; args.recycle(); AccessibilityNodeInfo focused = null; @@ -457,6 +472,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(focused, interactiveRegion); callback.setFindAccessibilityNodeInfoResult(focused, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -464,7 +480,8 @@ final class AccessibilityInteractionController { } } - public void focusSearchClientThread(long accessibilityNodeId, int direction, int interactionId, + public void focusSearchClientThread(long accessibilityNodeId, int direction, + Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid, long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); @@ -477,6 +494,7 @@ final class AccessibilityInteractionController { args.argi3 = interactionId; args.arg1 = callback; args.arg2 = spec; + args.arg3 = interactiveRegion; message.obj = args; @@ -502,6 +520,7 @@ final class AccessibilityInteractionController { final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; final MagnificationSpec spec = (MagnificationSpec) args.arg2; + final Region interactiveRegion = (Region) args.arg3; args.recycle(); @@ -530,6 +549,7 @@ final class AccessibilityInteractionController { if (spec != null) { spec.recycle(); } + adjustIsVisibleToUserIfNeeded(next, interactiveRegion); callback.setFindAccessibilityNodeInfoResult(next, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -644,6 +664,30 @@ final class AccessibilityInteractionController { } } + private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos, + Region interactiveRegion) { + if (interactiveRegion == null || infos == null) { + return; + } + final int infoCount = infos.size(); + for (int i = 0; i < infoCount; i++) { + AccessibilityNodeInfo info = infos.get(i); + adjustIsVisibleToUserIfNeeded(info, interactiveRegion); + } + } + + private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info, + Region interactiveRegion) { + if (interactiveRegion == null || info == null) { + return; + } + Rect boundsInScreen = mTempRect; + info.getBoundsInScreen(boundsInScreen); + if (interactiveRegion.quickReject(boundsInScreen)) { + info.setVisibleToUser(false); + } + } + private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info, MagnificationSpec spec) { if (info == null) { diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 964b054..0701b53 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -660,8 +660,96 @@ public class KeyEvent extends InputEvent implements Parcelable { /** Key code constant: Voice Assist key. * Launches the global voice assist activity. Not delivered to applications. */ public static final int KEYCODE_VOICE_ASSIST = 231; - - private static final int LAST_KEYCODE = KEYCODE_VOICE_ASSIST; + /** Key code constant: Radio key. + * Toggles TV service / Radio service. */ + public static final int KEYCODE_TV_RADIO_SERVICE = 232; + /** Key code constant: Teletext key. + * Displays Teletext service. */ + public static final int KEYCODE_TV_TELETEXT = 233; + /** Key code constant: Number entry key. + * Initiates to enter multi-digit channel nubmber when each digit key is assigned + * for selecting separate channel. Corresponds to Number Entry Mode (0x1D) of CEC + * User Control Code. */ + public static final int KEYCODE_TV_NUMBER_ENTRY = 234; + /** Key code constant: Analog Terrestrial key. + * Switches to analog terrestrial broadcast service. */ + public static final int KEYCODE_TV_TERRESTRIAL_ANALOG = 235; + /** Key code constant: Digital Terrestrial key. + * Switches to digital terrestrial broadcast service. */ + public static final int KEYCODE_TV_TERRESTRIAL_DIGITAL = 236; + /** Key code constant: Satellite key. + * Switches to digital satellite broadcast service. */ + public static final int KEYCODE_TV_SATELLITE = 237; + /** Key code constant: BS key. + * Switches to BS digital satellite broadcasting service available in Japan. */ + public static final int KEYCODE_TV_SATELLITE_BS = 238; + /** Key code constant: CS key. + * Switches to CS digital satellite broadcasting service available in Japan. */ + public static final int KEYCODE_TV_SATELLITE_CS = 239; + /** Key code constant: BS/CS key. + * Toggles between BS and CS digital satellite services. */ + public static final int KEYCODE_TV_SATELLITE_SERVICE = 240; + /** Key code constant: Toggle Network key. + * Toggles selecting broacast services. */ + public static final int KEYCODE_TV_NETWORK = 241; + /** Key code constant: Antenna/Cable key. + * Toggles broadcast input source between antenna and cable. */ + public static final int KEYCODE_TV_ANTENNA_CABLE = 242; + /** Key code constant: HDMI #1 key. + * Switches to HDMI input #1. */ + public static final int KEYCODE_TV_INPUT_HDMI_1 = 243; + /** Key code constant: HDMI #2 key. + * Switches to HDMI input #2. */ + public static final int KEYCODE_TV_INPUT_HDMI_2 = 244; + /** Key code constant: HDMI #3 key. + * Switches to HDMI input #3. */ + public static final int KEYCODE_TV_INPUT_HDMI_3 = 245; + /** Key code constant: HDMI #4 key. + * Switches to HDMI input #4. */ + public static final int KEYCODE_TV_INPUT_HDMI_4 = 246; + /** Key code constant: Composite #1 key. + * Switches to composite video input #1. */ + public static final int KEYCODE_TV_INPUT_COMPOSITE_1 = 247; + /** Key code constant: Composite #2 key. + * Switches to composite video input #2. */ + public static final int KEYCODE_TV_INPUT_COMPOSITE_2 = 248; + /** Key code constant: Component #1 key. + * Switches to component video input #1. */ + public static final int KEYCODE_TV_INPUT_COMPONENT_1 = 249; + /** Key code constant: Component #2 key. + * Switches to component video input #2. */ + public static final int KEYCODE_TV_INPUT_COMPONENT_2 = 250; + /** Key code constant: VGA #1 key. + * Switches to VGA (analog RGB) input #1. */ + public static final int KEYCODE_TV_INPUT_VGA_1 = 251; + /** Key code constant: Audio description key. + * Toggles audio description off / on. */ + public static final int KEYCODE_TV_AUDIO_DESCRIPTION = 252; + /** Key code constant: Audio description mixing volume up key. + * Louden audio description volume as compared with normal audio volume. */ + public static final int KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253; + /** Key code constant: Audio description mixing volume down key. + * Lessen audio description volume as compared with normal audio volume. */ + public static final int KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254; + /** Key code constant: Zoom mode key. + * Changes Zoom mode (Normal, Full, Zoom, Wide-zoom, etc.) */ + public static final int KEYCODE_TV_ZOOM_MODE = 255; + /** Key code constant: Contents menu key. + * Goes to the title list. Corresponds to Contents Menu (0x0B) of CEC User Control + * Code */ + public static final int KEYCODE_TV_CONTENTS_MENU = 256; + /** Key code constant: Media context menu key. + * Goes to the context menu of media contents. Corresponds to Media Context-sensitive + * Menu (0x11) of CEC User Control Code. */ + public static final int KEYCODE_TV_MEDIA_CONTEXT_MENU = 257; + /** Key code constant: Timer programming key. + * Goes to the timer recording menu. Corresponds to Timer Programming (0x54) of + * CEC User Control Code. */ + public static final int KEYCODE_TV_TIMER_PROGRAMMING = 258; + /** Key code constant: Help key. */ + public static final int KEYCODE_HELP = 259; + + private static final int LAST_KEYCODE = KEYCODE_HELP; // NOTE: If you add a new keycode here you must also add it to: // isSystem() diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 063a08d..7dcad68 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -149,9 +149,9 @@ public final class PointerIcon implements Parcelable { * Creates a custom pointer from the given bitmap and hotspot information. * * @param bitmap The bitmap for the icon. - * @param hotspotX The X offset of the pointer icon hotspot in the bitmap. + * @param hotSpotX The X offset of the pointer icon hotspot in the bitmap. * Must be within the [0, bitmap.getWidth()) range. - * @param hotspotY The Y offset of the pointer icon hotspot in the bitmap. + * @param hotSpotY The Y offset of the pointer icon hotspot in the bitmap. * Must be within the [0, bitmap.getHeight()) range. * @return A pointer icon for this bitmap. * @@ -374,18 +374,18 @@ public final class PointerIcon implements Parcelable { } private void loadResource(Context context, Resources resources, int resourceId) { - XmlResourceParser parser = resources.getXml(resourceId); + final XmlResourceParser parser = resources.getXml(resourceId); final int bitmapRes; final float hotSpotX; final float hotSpotY; try { XmlUtils.beginDocument(parser, "pointer-icon"); - TypedArray a = resources.obtainAttributes( + final TypedArray a = resources.obtainAttributes( parser, com.android.internal.R.styleable.PointerIcon); bitmapRes = a.getResourceId(com.android.internal.R.styleable.PointerIcon_bitmap, 0); - hotSpotX = a.getFloat(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0); - hotSpotY = a.getFloat(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0); + hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0); + hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0); a.recycle(); } catch (Exception ex) { throw new IllegalArgumentException("Exception parsing pointer icon resource.", ex); diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index ca08ecc..5d2822d 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -126,7 +126,7 @@ public class ThreadedRenderer extends HardwareRenderer { void destroy() { mInitialized = false; updateEnabledState(null); - nDestroyCanvasAndSurface(mNativeProxy); + nDestroy(mNativeProxy); } private void updateEnabledState(Surface surface) { @@ -488,7 +488,7 @@ public class ThreadedRenderer extends HardwareRenderer { private static native void nSetOpaque(long nativeProxy, boolean opaque); private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos, long recordDuration, float density); - private static native void nDestroyCanvasAndSurface(long nativeProxy); + private static native void nDestroy(long nativeProxy); private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode); private static native void nInvokeFunctor(long functor, boolean waitForCompletion); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index fce6f0b..92ad4e8 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -444,16 +444,19 @@ import java.util.concurrent.atomic.AtomicInteger; * <a name="Drawing"></a> * <h3>Drawing</h3> * <p> - * Drawing is handled by walking the tree and rendering each view that - * intersects the invalid region. Because the tree is traversed in-order, - * this means that parents will draw before (i.e., behind) their children, with - * siblings drawn in the order they appear in the tree. - * If you set a background drawable for a View, then the View will draw it for you - * before calling back to its <code>onDraw()</code> method. + * Drawing is handled by walking the tree and recording the drawing commands of + * any View that needs to update. After this, the drawing commands of the + * entire tree are issued to screen, clipped to the newly damaged area. * </p> * * <p> - * Note that the framework will not draw views that are not in the invalid region. + * The tree is largely recorded and drawn in order, with parents drawn before + * (i.e., behind) their children, with siblings drawn in the order they appear + * in the tree. If you set a background drawable for a View, then the View will + * draw it before calling back to its <code>onDraw()</code> method. The child + * drawing order can be overridden with + * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} + * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. * </p> * * <p> @@ -4908,36 +4911,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } onFocusChanged(true, direction, previouslyFocusedRect); - manageFocusHotspot(true, oldFocus); refreshDrawableState(); } } /** - * Forwards focus information to the background drawable, if necessary. When - * the view is gaining focus, <code>v</code> is the previous focus holder. - * When the view is losing focus, <code>v</code> is the next focus holder. - * - * @param focused whether this view is focused - * @param v previous or the next focus holder, or null if none - */ - private void manageFocusHotspot(boolean focused, View v) { - final Rect r = new Rect(); - if (v != null && mAttachInfo != null) { - v.getHotspotBounds(r); - final int[] location = mAttachInfo.mTmpLocation; - getLocationOnScreen(location); - r.offset(-location[0], -location[1]); - } else { - r.set(0, 0, mRight - mLeft, mBottom - mTop); - } - - final float x = r.exactCenterX(); - final float y = r.exactCenterY(); - drawableHotspotChanged(x, y); - } - - /** * Populates <code>outRect</code> with the hotspot bounds. By default, * the hotspot bounds are identical to the screen bounds. * @@ -5060,8 +5038,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } onFocusChanged(false, 0, null); - - manageFocusHotspot(false, focused); refreshDrawableState(); if (propagate && (!refocus || !rootViewRequestFocus())) { @@ -10852,6 +10828,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Sets whether the View's Outline should be used to clip the contents of the View. * <p> + * Only a single non-rectangular clip can be applied on a View at any time. + * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) + * circular reveal} animation take priority over Outline clipping, and + * child Outline clipping takes priority over Outline clipping done by a + * parent. + * <p> * Note that this flag will only be respected if the View's Outline returns true from * {@link Outline#canClip()}. * @@ -15118,10 +15100,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, bounds.set(0, 0, mRight - mLeft, mBottom - mTop); } + canvas.save(); canvas.translate(mScrollX, mScrollY); + canvas.clipRect(bounds, Region.Op.REPLACE); drawable.setBounds(bounds); drawable.draw(canvas); - canvas.translate(-mScrollX, -mScrollY); + canvas.restore(); } /** diff --git a/core/java/android/view/ViewAnimationUtils.java b/core/java/android/view/ViewAnimationUtils.java index 7ced088..001cd01 100644 --- a/core/java/android/view/ViewAnimationUtils.java +++ b/core/java/android/view/ViewAnimationUtils.java @@ -27,9 +27,13 @@ public final class ViewAnimationUtils { private ViewAnimationUtils() {} /** * Returns an Animator which can animate a clipping circle. - * + * <p> * Any shadow cast by the View will respect the circular clip from this animator. - * + * <p> + * Only a single non-rectangular clip can be applied on a View at any time. + * Views clipped by a circular reveal animation take priority over + * {@link View#setClipToOutline(boolean) View Outline clipping}. + * <p> * Note that the animation returned here is a one-shot animation. It cannot * be re-used, and once started it cannot be paused or resumed. * @@ -39,7 +43,7 @@ public final class ViewAnimationUtils { * @param startRadius The starting radius of the animating circle. * @param endRadius The ending radius of the animating circle. */ - public static final Animator createCircularReveal(View view, + public static Animator createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius) { return new RevealAnimator(view, centerX, centerY, startRadius, endRadius); } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index adad082..974fe4e 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5034,6 +5034,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Tells the ViewGroup whether to draw its children in the order defined by the method * {@link #getChildDrawingOrder(int, int)}. + * <p> + * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)}, + * will override custom child ordering done via this method. * * @param enabled true if the order of the children when drawing is determined by * {@link #getChildDrawingOrder(int, int)}, false otherwise diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 49d925f..4299e2e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6111,6 +6111,33 @@ public final class ViewRootImpl implements ViewParent, } } } break; + + + case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: { + if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView != null) { + // We care only for changes rooted in the focused host. + final long eventSourceId = event.getSourceNodeId(); + final int hostViewId = AccessibilityNodeInfo.getAccessibilityViewId( + eventSourceId); + if (hostViewId != mAccessibilityFocusedHost.getAccessibilityViewId()) { + break; + } + + // We only care about changes that may change the virtual focused view bounds. + final int changes = event.getContentChangeTypes(); + if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) != 0 + || changes == AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) { + AccessibilityNodeProvider provider = mAccessibilityFocusedHost + .getAccessibilityNodeProvider(); + if (provider != null) { + final int virtualChildId = AccessibilityNodeInfo.getVirtualDescendantId( + mAccessibilityFocusedVirtualView.getSourceNodeId()); + mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo( + virtualChildId); + } + } + } + } break; } mAccessibilityManager.sendAccessibilityEvent(event); return true; @@ -6629,14 +6656,15 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, - int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, + Region interactiveRegion, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId, - interactionId, callback, flags, interrogatingPid, interrogatingTid, - spec); + interactiveRegion, interactionId, callback, flags, interrogatingPid, + interrogatingTid, spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -6669,15 +6697,15 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, - String viewId, int interactionId, + String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId, - viewId, interactionId, callback, flags, interrogatingPid, - interrogatingTid, spec); + viewId, interactiveRegion, interactionId, callback, flags, + interrogatingPid, interrogatingTid, spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -6690,14 +6718,15 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, - int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, + Region interactiveRegion, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text, - interactionId, callback, flags, interrogatingPid, interrogatingTid, - spec); + interactiveRegion, interactionId, callback, flags, interrogatingPid, + interrogatingTid, spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -6709,14 +6738,15 @@ public final class ViewRootImpl implements ViewParent, } @Override - public void findFocus(long accessibilityNodeId, int focusType, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int flags, + public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, + int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() - .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback, - flags, interrogatingPid, interrogatingTid, spec); + .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion, + interactionId, callback, flags, interrogatingPid, interrogatingTid, + spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -6728,14 +6758,15 @@ public final class ViewRootImpl implements ViewParent, } @Override - public void focusSearch(long accessibilityNodeId, int direction, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int flags, + public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, + int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() - .focusSearchClientThread(accessibilityNodeId, direction, interactionId, - callback, flags, interrogatingPid, interrogatingTid, spec); + .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion, + interactionId, callback, flags, interrogatingPid, interrogatingTid, + spec); } else { // We cannot make the call and notify the caller so it does not wait. try { diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 9b6f200..ebc683a 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1430,7 +1430,9 @@ public abstract class Window { * {@link android.transition.Visibility} as entering is governed by changing visibility from * {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null, * entering Views will remain unaffected. + * * @param transition The Transition to use to move Views into the initial Scene. + * @attr ref android.R.styleable#Window_windowEnterTransition */ public void setEnterTransition(Transition transition) {} @@ -1444,8 +1446,10 @@ public abstract class Window { * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null, * entering Views will remain unaffected. If nothing is set, the default will be to * use the same value as set in {@link #setEnterTransition(android.transition.Transition)}. + * * @param transition The Transition to use to move Views out of the Scene when the Window * is preparing to close. + * @attr ref android.R.styleable#Window_windowReturnTransition */ public void setReturnTransition(Transition transition) {} @@ -1456,8 +1460,10 @@ public abstract class Window { * {@link android.transition.Visibility} as exiting is governed by changing visibility * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will * remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use to move Views out of the scene when calling a * new Activity. + * @attr ref android.R.styleable#Window_windowExitTransition */ public void setExitTransition(Transition transition) {} @@ -1470,8 +1476,10 @@ public abstract class Window { * the views will remain unaffected. If nothing is set, the default will be to use the same * transition as {@link #setExitTransition(android.transition.Transition)}. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use to move Views into the scene when reentering from a * previously-started Activity. + * @attr ref android.R.styleable#Window_windowReenterTransition */ public void setReenterTransition(Transition transition) {} @@ -1484,6 +1492,7 @@ public abstract class Window { * entering Views will remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. * * @return the Transition to use to move Views into the initial Scene. + * @attr ref android.R.styleable#Window_windowEnterTransition */ public Transition getEnterTransition() { return null; } @@ -1495,8 +1504,10 @@ public abstract class Window { * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend * {@link android.transition.Visibility} as entering is governed by changing visibility from * {@link View#VISIBLE} to {@link View#INVISIBLE}. + * * @return The Transition to use to move Views out of the Scene when the Window * is preparing to close. + * @attr ref android.R.styleable#Window_windowReturnTransition */ public Transition getReturnTransition() { return null; } @@ -1507,8 +1518,10 @@ public abstract class Window { * {@link android.transition.Visibility} as exiting is governed by changing visibility * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will * remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @return the Transition to use to move Views out of the scene when calling a * new Activity. + * @attr ref android.R.styleable#Window_windowExitTransition */ public Transition getExitTransition() { return null; } @@ -1519,8 +1532,10 @@ public abstract class Window { * will extend {@link android.transition.Visibility} as exiting is governed by changing * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @return The Transition to use to move Views into the scene when reentering from a * previously-started Activity. + * @attr ref android.R.styleable#Window_windowReenterTransition */ public Transition getReenterTransition() { return null; } @@ -1530,8 +1545,10 @@ public abstract class Window { * {@link android.transition.ChangeBounds}. A null * value will cause transferred shared elements to blink to the final position. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use for shared elements transferred into the content * Scene. + * @attr ref android.R.styleable#Window_windowSharedElementEnterTransition */ public void setSharedElementEnterTransition(Transition transition) {} @@ -1543,22 +1560,28 @@ public abstract class Window { * If no value is set, the default will be to use the same value as * {@link #setSharedElementEnterTransition(android.transition.Transition)}. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use for shared elements transferred out of the content * Scene. + * @attr ref android.R.styleable#Window_windowSharedElementReturnTransition */ public void setSharedElementReturnTransition(Transition transition) {} /** * Returns the Transition that will be used for shared elements transferred into the content * Scene. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @return Transition to use for sharend elements transferred into the content Scene. + * @attr ref android.R.styleable#Window_windowSharedElementEnterTransition */ public Transition getSharedElementEnterTransition() { return null; } /** * Returns the Transition that will be used for shared elements transferred back to a * calling Activity. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @return Transition to use for sharend elements transferred into the content Scene. + * @attr ref android.R.styleable#Window_windowSharedElementReturnTransition */ public Transition getSharedElementReturnTransition() { return null; } @@ -1568,8 +1591,10 @@ public abstract class Window { * must animate during the exit transition, this Transition should be used. Upon completion, * the shared elements may be transferred to the started Activity. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use for shared elements in the launching Window * prior to transferring to the launched Activity's Window. + * @attr ref android.R.styleable#Window_windowSharedElementExitTransition */ public void setSharedElementExitTransition(Transition transition) {} @@ -1579,8 +1604,10 @@ public abstract class Window { * is set, this will default to * {@link #setSharedElementExitTransition(android.transition.Transition)}. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * * @param transition The Transition to use for shared elements in the launching Window * after the shared element has returned to the Window. + * @attr ref android.R.styleable#Window_windowSharedElementReenterTransition */ public void setSharedElementReenterTransition(Transition transition) {} @@ -1591,6 +1618,7 @@ public abstract class Window { * * @return the Transition to use for shared elements in the launching Window prior * to transferring to the launched Activity's Window. + * @attr ref android.R.styleable#Window_windowSharedElementExitTransition */ public Transition getSharedElementExitTransition() { return null; } @@ -1601,6 +1629,7 @@ public abstract class Window { * * @return the Transition that will be used for shared elements reentering from a started * Activity after it has returned the shared element to it start location. + * @attr ref android.R.styleable#Window_windowSharedElementReenterTransition */ public Transition getSharedElementReenterTransition() { return null; } @@ -1610,8 +1639,10 @@ public abstract class Window { * transition of the calling Activity. When true, the transition will start as soon as possible. * When false, the transition will wait until the remote exiting transition completes before * starting. + * * @param allow true to start the enter transition when possible or false to * wait until the exiting transition completes. + * @attr ref android.R.styleable#Window_windowAllowEnterTransitionOverlap */ public void setAllowEnterTransitionOverlap(boolean allow) {} @@ -1621,8 +1652,10 @@ public abstract class Window { * transition of the calling Activity. When true, the transition will start as soon as possible. * When false, the transition will wait until the remote exiting transition completes before * starting. + * * @return true when the enter transition should start as soon as possible or false to * when it should wait until the exiting transition completes. + * @attr ref android.R.styleable#Window_windowAllowEnterTransitionOverlap */ public boolean getAllowEnterTransitionOverlap() { return true; } @@ -1632,10 +1665,20 @@ public abstract class Window { * transition of the called Activity when reentering after if finishes. When true, * the transition will start as soon as possible. When false, the transition will wait * until the called Activity's exiting transition completes before starting. + * * @param allow true to start the transition when possible or false to wait until the * called Activity's exiting transition completes. + * @attr ref android.R.styleable#Window_windowAllowReturnTransitionOverlap */ - public void setAllowExitTransitionOverlap(boolean allow) {} + public void setAllowReturnTransitionOverlap(boolean allow) {} + + /** + * TODO: remove this. + * @hide + */ + public void setAllowExitTransitionOverlap(boolean allow) { + setAllowReturnTransitionOverlap(allow); + } /** * Returns how the transition set in @@ -1643,10 +1686,18 @@ public abstract class Window { * transition of the called Activity when reentering after if finishes. When true, * the transition will start as soon as possible. When false, the transition will wait * until the called Activity's exiting transition completes before starting. + * * @return true when the transition should start when possible or false when it should wait * until the called Activity's exiting transition completes. + * @attr ref android.R.styleable#Window_windowAllowReturnTransitionOverlap */ - public boolean getAllowExitTransitionOverlap() { return true; } + public boolean getAllowReturnTransitionOverlap() { return true; } + + /** + * TODO: remove this. + * @hide + */ + public boolean getAllowExitTransitionOverlap() { return getAllowReturnTransitionOverlap(); } /** * Returns the duration, in milliseconds, of the window background fade @@ -1654,8 +1705,10 @@ public abstract class Window { * <p>When executing the enter transition, the background starts transparent * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is * 300 milliseconds.</p> + * * @return The duration of the window background fade to opaque during enter transition. * @see #getEnterTransition() + * @attr ref android.R.styleable#Window_windowTransitionBackgroundFadeDuration */ public long getTransitionBackgroundFadeDuration() { return 0; } @@ -1665,9 +1718,11 @@ public abstract class Window { * <p>When executing the enter transition, the background starts transparent * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is * 300 milliseconds.</p> + * * @param fadeDurationMillis The duration of the window background fade to or from opaque * during enter transition. * @see #setEnterTransition(android.transition.Transition) + * @attr ref android.R.styleable#Window_windowTransitionBackgroundFadeDuration */ public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { } @@ -1679,6 +1734,7 @@ public abstract class Window { * @return <code>true</code> when shared elements should use an Overlay during * shared element transitions or <code>false</code> when they should animate as * part of the normal View hierarchy. + * @attr ref android.R.styleable#Window_windowSharedElementsUseOverlay */ public boolean getSharedElementsUseOverlay() { return true; } @@ -1689,6 +1745,7 @@ public abstract class Window { * @param sharedElementsUseOverlay <code>true</code> indicates that shared elements should * be transitioned with an Overlay or <code>false</code> * to transition within the normal View hierarchy. + * @attr ref android.R.styleable#Window_windowSharedElementsUseOverlay */ public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) { } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 053fdd0..b7b12a8 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -379,6 +379,10 @@ public interface WindowManagerPolicy { public static final int LID_CLOSED = 0; public static final int LID_OPEN = 1; + public static final int CAMERA_LENS_COVER_ABSENT = -1; + public static final int CAMERA_LENS_UNCOVERED = 0; + public static final int CAMERA_LENS_COVERED = 1; + /** * Ask the window manager to re-evaluate the system UI flags. */ @@ -399,6 +403,11 @@ public interface WindowManagerPolicy { public int getLidState(); /** + * Returns a code that descripbes whether the camera lens is covered or not. + */ + public int getCameraLensCoverState(); + + /** * Switch the keyboard layout for the given device. * Direction should be +1 or -1 to go to the next or previous keyboard layout. */ @@ -951,7 +960,14 @@ public interface WindowManagerPolicy { * @param lidOpen True if the lid is now open. */ public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); - + + /** + * Tell the policy that the camera lens has been covered or uncovered. + * @param whenNanos The time when the change occurred in uptime nanoseconds. + * @param lensCovered True if the lens is covered. + */ + public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered); + /** * Tell the policy if anyone is requesting that keyguard not come on. * diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl index 8d15472..faf7789 100644 --- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl +++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl @@ -16,6 +16,7 @@ package android.view.accessibility; +import android.graphics.Region; import android.os.Bundle; import android.view.MagnificationSpec; import android.view.accessibility.AccessibilityNodeInfo; @@ -29,23 +30,23 @@ import android.view.accessibility.IAccessibilityInteractionConnectionCallback; */ oneway interface IAccessibilityInteractionConnection { - void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid, in MagnificationSpec spec); + void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, in Region bounds, + int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, + int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, + in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback, + int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); + + void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); - void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid, in MagnificationSpec spec); - - void findFocus(long accessibilityNodeId, int focusType, int interactionId, + void findFocus(long accessibilityNodeId, int focusType, in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); - void focusSearch(long accessibilityNodeId, int direction, int interactionId, + void focusSearch(long accessibilityNodeId, int direction, in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec); diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index 4d2f57a..20adfe4 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -431,7 +431,15 @@ public class BaseInputConnection implements InputConnection { /** * The default implementation does nothing. */ - public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + public boolean requestCursorUpdates(int cursorUpdateMode) { + return false; + } + + /** + * The default implementation does nothing. + * @removed + */ + public final boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { return false; } diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java index 0492824..fe0f5b9 100644 --- a/core/java/android/view/inputmethod/CursorAnchorInfo.java +++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java @@ -45,9 +45,9 @@ public final class CursorAnchorInfo implements Parcelable { private final CharSequence mComposingText; /** - * {@code True} if the insertion marker is partially or entirely clipped by other UI elements. + * Flags of the insertion marker. See {@link #FLAG_HAS_VISIBLE_REGION} for example. */ - private final boolean mInsertionMarkerClipped; + private final int mInsertionMarkerFlags; /** * Horizontal position of the insertion marker, in the local coordinates that will be * transformed with the transformation matrix when rendered on the screen. This should be @@ -90,27 +90,47 @@ public final class CursorAnchorInfo implements Parcelable { */ private final Matrix mMatrix; + /** + * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterRectFlags(int)}: the + * insertion marker or character bounds have at least one visible region. + */ + public static final int FLAG_HAS_VISIBLE_REGION = 0x01; + + /** + * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterRectFlags(int)}: the + * insertion marker or character bounds have at least one invisible (clipped) region. + */ + public static final int FLAG_HAS_INVISIBLE_REGION = 0x02; + + /** + * @removed + */ public static final int CHARACTER_RECT_TYPE_MASK = 0x0f; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this * character. Editor authors should not use this flag. + * @removed */ public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible. + * @removed */ public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible. + * @removed */ public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible. + * @removed */ public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3; /** * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle * for this character. Input method authors should ignore the returned rectangle. + * @removed */ public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4; @@ -119,7 +139,7 @@ public final class CursorAnchorInfo implements Parcelable { mSelectionEnd = source.readInt(); mComposingTextStart = source.readInt(); mComposingText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); - mInsertionMarkerClipped = (source.readInt() != 0); + mInsertionMarkerFlags = source.readInt(); mInsertionMarkerHorizontal = source.readFloat(); mInsertionMarkerTop = source.readFloat(); mInsertionMarkerBaseline = source.readFloat(); @@ -141,7 +161,7 @@ public final class CursorAnchorInfo implements Parcelable { dest.writeInt(mSelectionEnd); dest.writeInt(mComposingTextStart); TextUtils.writeToParcel(mComposingText, dest, flags); - dest.writeInt(mInsertionMarkerClipped ? 1 : 0); + dest.writeInt(mInsertionMarkerFlags); dest.writeFloat(mInsertionMarkerHorizontal); dest.writeFloat(mInsertionMarkerTop); dest.writeFloat(mInsertionMarkerBaseline); @@ -159,7 +179,7 @@ public final class CursorAnchorInfo implements Parcelable { + mInsertionMarkerBaseline + mInsertionMarkerBottom; int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash); hash *= 31; - hash += (mInsertionMarkerClipped ? 2 : 1); + hash += mInsertionMarkerFlags; hash *= 31; hash += mSelectionStart + mSelectionEnd + mComposingTextStart; hash *= 31; @@ -204,7 +224,7 @@ public final class CursorAnchorInfo implements Parcelable { || !Objects.equals(mComposingText, that.mComposingText)) { return false; } - if (mInsertionMarkerClipped != that.mInsertionMarkerClipped + if (mInsertionMarkerFlags != that.mInsertionMarkerFlags || !areSameFloatImpl(mInsertionMarkerHorizontal, that.mInsertionMarkerHorizontal) || !areSameFloatImpl(mInsertionMarkerTop, that.mInsertionMarkerTop) || !areSameFloatImpl(mInsertionMarkerBaseline, that.mInsertionMarkerBaseline) @@ -225,7 +245,7 @@ public final class CursorAnchorInfo implements Parcelable { return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd + " mComposingTextStart=" + mComposingTextStart + " mComposingText=" + Objects.toString(mComposingText) - + " mInsertionMarkerClipped=" + mInsertionMarkerClipped + + " mInsertionMarkerFlags=" + mInsertionMarkerFlags + " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal + " mInsertionMarkerTop=" + mInsertionMarkerTop + " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline @@ -272,6 +292,20 @@ public final class CursorAnchorInfo implements Parcelable { private CharSequence mComposingText = null; /** + * @removed + */ + public Builder setInsertionMarkerLocation(final float horizontalPosition, + final float lineTop, final float lineBaseline, final float lineBottom, + final boolean clipped){ + mInsertionMarkerHorizontal = horizontalPosition; + mInsertionMarkerTop = lineTop; + mInsertionMarkerBaseline = lineBaseline; + mInsertionMarkerBottom = lineBottom; + mInsertionMarkerFlags = clipped ? FLAG_HAS_INVISIBLE_REGION : 0; + return this; + } + + /** * Sets the location of the text insertion point (zero width cursor) as a rectangle in * local coordinates. Calling this can be skipped when there is no text insertion point; * however if there is an insertion point, editors must call this method. @@ -288,24 +322,24 @@ public final class CursorAnchorInfo implements Parcelable { * @param lineBottom vertical position of the insertion marker, in the local coordinates * that will be transformed with the transformation matrix when rendered on the screen. This * should be calculated or compatible with {@link Layout#getLineBottom(int)}. - * @param clipped {@code true} is the insertion marker is partially or entierly clipped by - * other UI elements. + * @param flags flags of the insertion marker. See {@link #FLAG_HAS_VISIBLE_REGION} for + * example. */ public Builder setInsertionMarkerLocation(final float horizontalPosition, final float lineTop, final float lineBaseline, final float lineBottom, - final boolean clipped){ + final int flags){ mInsertionMarkerHorizontal = horizontalPosition; mInsertionMarkerTop = lineTop; mInsertionMarkerBaseline = lineBaseline; mInsertionMarkerBottom = lineBottom; - mInsertionMarkerClipped = clipped; + mInsertionMarkerFlags = flags; return this; } private float mInsertionMarkerHorizontal = Float.NaN; private float mInsertionMarkerTop = Float.NaN; private float mInsertionMarkerBaseline = Float.NaN; private float mInsertionMarkerBottom = Float.NaN; - private boolean mInsertionMarkerClipped = false; + private int mInsertionMarkerFlags = 0; /** * Adds the bounding box of the character specified with the index. @@ -320,8 +354,8 @@ public final class CursorAnchorInfo implements Parcelable { * coordinates, that is, right edge for LTR text and left edge for RTL text. * @param trailingEdgeY y coordinate of the trailing edge of the character in local * coordinates. - * @param flags type and flags for this character. See - * {@link #CHARACTER_RECT_TYPE_FULLY_VISIBLE} for example. + * @param flags flags for this character rect. See {@link #FLAG_HAS_VISIBLE_REGION} for + * example. * @throws IllegalArgumentException If the index is a negative value, or not greater than * all of the previously called indices. */ @@ -331,11 +365,6 @@ public final class CursorAnchorInfo implements Parcelable { if (index < 0) { throw new IllegalArgumentException("index must not be a negative integer."); } - final int type = flags & CHARACTER_RECT_TYPE_MASK; - if (type == CHARACTER_RECT_TYPE_UNSPECIFIED) { - throw new IllegalArgumentException("Type except for " - + "CHARACTER_RECT_TYPE_UNSPECIFIED must be specified."); - } if (mCharacterRectBuilder == null) { mCharacterRectBuilder = new SparseRectFArrayBuilder(); } @@ -388,7 +417,7 @@ public final class CursorAnchorInfo implements Parcelable { mSelectionEnd = -1; mComposingTextStart = -1; mComposingText = null; - mInsertionMarkerClipped = false; + mInsertionMarkerFlags = 0; mInsertionMarkerHorizontal = Float.NaN; mInsertionMarkerTop = Float.NaN; mInsertionMarkerBaseline = Float.NaN; @@ -406,7 +435,7 @@ public final class CursorAnchorInfo implements Parcelable { mSelectionEnd = builder.mSelectionEnd; mComposingTextStart = builder.mComposingTextStart; mComposingText = builder.mComposingText; - mInsertionMarkerClipped = builder.mInsertionMarkerClipped; + mInsertionMarkerFlags = builder.mInsertionMarkerFlags; mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal; mInsertionMarkerTop = builder.mInsertionMarkerTop; mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline; @@ -449,11 +478,20 @@ public final class CursorAnchorInfo implements Parcelable { } /** + * Returns the flag of the insertion marker. + * @return the flag of the insertion marker. {@code 0} if no flag is specified. + */ + public int getInsertionMarkerFlags() { + return mInsertionMarkerFlags; + } + + /** * Returns the visibility of the insertion marker. * @return {@code true} if the insertion marker is partially or entirely clipped. + * @removed */ public boolean isInsertionMarkerClipped() { - return mInsertionMarkerClipped; + return (mInsertionMarkerFlags & FLAG_HAS_VISIBLE_REGION) != 0; } /** @@ -522,17 +560,17 @@ public final class CursorAnchorInfo implements Parcelable { } /** - * Returns the flags associated with the character specified with the index. + * Returns the flags associated with the character rect specified with the index. * @param index index of the character in a Java chars. - * @return {@link #CHARACTER_RECT_TYPE_UNSPECIFIED} if no flag is specified. + * @return {@code 0} if no flag is specified. */ // TODO: Prepare a document about the expected behavior for surrogate pairs, combining // characters, and non-graphical chars. public int getCharacterRectFlags(final int index) { if (mCharacterRects == null) { - return CHARACTER_RECT_TYPE_UNSPECIFIED; + return 0; } - return mCharacterRects.getFlags(index, CHARACTER_RECT_TYPE_UNSPECIFIED); + return mCharacterRects.getFlags(index, 0); } /** diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java index ca094c1..093fb2f 100644 --- a/core/java/android/view/inputmethod/InputConnection.java +++ b/core/java/android/view/inputmethod/InputConnection.java @@ -728,31 +728,47 @@ public interface InputConnection { * The editor is requested to call * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} at * once, as soon as possible, regardless of cursor/anchor position changes. This flag can be - * used together with {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR}. + * used together with {@link #CURSOR_UPDATE_MONITOR}. */ - public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE = 1 << 0; + public static final int CURSOR_UPDATE_IMMEDIATE = 1 << 0; /** * The editor is requested to call * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} * whenever cursor/anchor position is changed. To disable monitoring, call - * {@link InputConnection#requestUpdateCursorAnchorInfo(int)} again with this flag off. + * {@link InputConnection#requestCursorUpdates(int)} again with this flag off. * <p> - * This flag can be used together with {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE}. + * This flag can be used together with {@link #CURSOR_UPDATE_IMMEDIATE}. * </p> */ - public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR = 1 << 1; + public static final int CURSOR_UPDATE_MONITOR = 1 << 1; /** * Called by the input method to ask the editor for calling back * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} to * notify cursor/anchor locations. * - * @param cursorUpdateMode {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE} and/or - * {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR} + * @param cursorUpdateMode {@link #CURSOR_UPDATE_IMMEDIATE} and/or + * {@link #CURSOR_UPDATE_MONITOR}. Pass {@code 0} to disable the effect of + * {@link #CURSOR_UPDATE_MONITOR}. * @return {@code true} if the request is scheduled. {@code false} to indicate that when the * application will not call * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}. */ + public boolean requestCursorUpdates(int cursorUpdateMode); + + /** + * @removed + */ + public static final int REQUEST_UPDATE_CURSOR_UPDATE_IMMEDIATE = 1 << 0; + + /** + * @removed + */ + public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR = 1 << 1; + + /** + * @removed + */ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode); } diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java index d95df25..87853de 100644 --- a/core/java/android/view/inputmethod/InputConnectionWrapper.java +++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java @@ -126,7 +126,14 @@ public class InputConnectionWrapper implements InputConnection { return mTarget.performPrivateCommand(action, data); } - public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { - return mTarget.requestUpdateCursorAnchorInfo(cursorUpdateMode); + public boolean requestCursorUpdates(int cursorUpdateMode) { + return mTarget.requestCursorUpdates(cursorUpdateMode); } - } + + /** + * @removed + */ + public final boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + return mTarget.requestCursorUpdates(cursorUpdateMode); + } +} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 0a472c7..b56378f 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1526,7 +1526,7 @@ public final class InputMethodManager { * Return true if the current input method wants to watch the location * of the input editor's cursor in its window. * - * @deprecated Use {@link InputConnection#requestUpdateCursorAnchorInfo(int)} instead. + * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead. */ @Deprecated public boolean isWatchingCursor(View view) { @@ -1542,9 +1542,9 @@ public final class InputMethodManager { public boolean isCursorAnchorInfoEnabled() { synchronized (mH) { final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & - InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0; + InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode & - InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR) != 0; + InputConnection.CURSOR_UPDATE_MONITOR) != 0; return isImmediate || isMonitoring; } } @@ -1608,7 +1608,7 @@ public final class InputMethodManager { // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has // not been changed from the previous call. final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & - InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0; + InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) { // TODO: Consider always emitting this message once we have addressed redundant // calls of this method from android.widget.Editor. @@ -1624,7 +1624,7 @@ public final class InputMethodManager { mCursorAnchorInfo = cursorAnchorInfo; // Clear immediate bit (if any). mRequestUpdateCursorAnchorInfoMonitorMode &= - ~InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE; + ~InputConnection.CURSOR_UPDATE_IMMEDIATE; } catch (RemoteException e) { Log.w(TAG, "IME died: " + mCurId, e); } diff --git a/core/java/android/webkit/WebResourceRequest.java b/core/java/android/webkit/WebResourceRequest.java index dc7c808..b46ac9a 100644 --- a/core/java/android/webkit/WebResourceRequest.java +++ b/core/java/android/webkit/WebResourceRequest.java @@ -41,7 +41,7 @@ public interface WebResourceRequest { boolean isForMainFrame(); /** - * Gets whether a gesture was associated with the request. + * Gets whether a gesture (such as a link click) was associated with the request. * <p> * <strong>IMPORTANT:</strong> * This should not be used to implement any form of security. It is possible for the content @@ -49,6 +49,11 @@ public interface WebResourceRequest { * * @return whether a gesture was associated with the request. */ + boolean hasGesture(); + + /* + * @removed + */ boolean hasUserGestureInsecure(); /** diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index e1f19ee..081bfdf 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -1810,21 +1810,6 @@ public class WebView extends AbsoluteLayout } /** - * Sets whether the application wants to opt out from using the Data Reduction Proxy - * service. - * Data reduction proxy can only be enabled by the user and will almost always be - * transparent to the application. In rare cases where using the proxy interferes - * with the app, the application developer can use this API to opt out from using the - * proxy. Note that this may increase network bandwidth usage. - * - * See <a href=http://developer.chrome.com/multidevice/data-compression> - * Data Compression Proxy</a> - */ - public static void optOutDataReductionProxy() { - getFactory().getStatics().optOutDataReductionProxy(); - } - - /** * Gets the list of currently loaded plugins. * * @return the list of currently loaded plugins @@ -1954,16 +1939,14 @@ public class WebView extends AbsoluteLayout * * @param zoomFactor the zoom factor to apply. The zoom factor will be clamped to the Webview's * zoom limits. This value must be in the range 0.01 to 100.0 inclusive. - * - * @return false if no zoom changes, true otherwise. */ - public boolean zoomBy(float zoomFactor) { + public void zoomBy(float zoomFactor) { checkThread(); if (zoomFactor < 0.01) throw new IllegalArgumentException("zoomFactor must be greater than 0.01."); if (zoomFactor > 100.0) throw new IllegalArgumentException("zoomFactor must be less than 100."); - return mProvider.zoomBy(zoomFactor); + mProvider.zoomBy(zoomFactor); } /** diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java index 48f3ca3..20bb932 100644 --- a/core/java/android/webkit/WebViewFactoryProvider.java +++ b/core/java/android/webkit/WebViewFactoryProvider.java @@ -61,12 +61,6 @@ public interface WebViewFactoryProvider { /** * Implements the API method: - * {@link android.webkit.WebView#optOutDataReductionProxy() } - */ - void optOutDataReductionProxy(); - - /** - * Implements the API method: * {@link android.webkit.WebView#setSlowWholeDocumentDrawEnabled(boolean) } */ void enableSlowWholeDocumentDraw(); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index eb93745..eef8554 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -5717,8 +5717,16 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } @Override + public boolean requestCursorUpdates(int cursorUpdateMode) { + return getTarget().requestCursorUpdates(cursorUpdateMode); + } + + /** + * @removed + */ + @Override public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { - return getTarget().requestUpdateCursorAnchorInfo(cursorUpdateMode); + return getTarget().requestCursorUpdates(cursorUpdateMode); } } diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java index 96abf51..6ca4a9e 100644 --- a/core/java/android/widget/ActionMenuView.java +++ b/core/java/android/widget/ActionMenuView.java @@ -29,6 +29,7 @@ import android.view.accessibility.AccessibilityEvent; import com.android.internal.view.menu.ActionMenuItemView; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuItemImpl; +import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; /** @@ -53,6 +54,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo private boolean mReserveOverflow; private ActionMenuPresenter mPresenter; + private MenuPresenter.Callback mActionMenuPresenterCallback; + private MenuBuilder.Callback mMenuBuilderCallback; private boolean mFormatItems; private int mFormatItemsWidth; private int mMinCellSize; @@ -608,7 +611,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo mMenu = new MenuBuilder(context); mMenu.setCallback(new MenuBuilderCallback()); mPresenter = new ActionMenuPresenter(context); - mPresenter.setCallback(new ActionMenuPresenterCallback()); + mPresenter.setCallback(mActionMenuPresenterCallback != null + ? mActionMenuPresenterCallback : new ActionMenuPresenterCallback()); mMenu.addMenuPresenter(mPresenter, mPopupContext); mPresenter.setMenuView(this); } @@ -617,6 +621,15 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo } /** + * Must be called before the first call to getMenu() + * @hide + */ + public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) { + mActionMenuPresenterCallback = pcb; + mMenuBuilderCallback = mcb; + } + + /** * Returns the current menu or null if one has not yet been configured. * @hide Internal use only for action bar integration */ @@ -719,6 +732,9 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo @Override public void onMenuModeChange(MenuBuilder menu) { + if (mMenuBuilderCallback != null) { + mMenuBuilderCallback.onMenuModeChange(menu); + } } } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 1da22ca..b9f891c 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -297,10 +297,10 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { public boolean performItemClick(View view, int position, long id) { if (mOnItemClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); + mOnItemClickListener.onItemClick(this, view, position, id); if (view != null) { view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } - mOnItemClickListener.onItemClick(this, view, position, id); return true; } diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 26c1f96..2729bd0 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -71,9 +71,9 @@ import libcore.icu.ICU; * @attr ref android.R.styleable#DatePicker_minDate * @attr ref android.R.styleable#DatePicker_spinnersShown * @attr ref android.R.styleable#DatePicker_calendarViewShown - * @attr ref android.R.styleable#DatePicker_dayOfWeekBackgroundColor + * @attr ref android.R.styleable#DatePicker_dayOfWeekBackground * @attr ref android.R.styleable#DatePicker_dayOfWeekTextAppearance - * @attr ref android.R.styleable#DatePicker_headerBackgroundColor + * @attr ref android.R.styleable#DatePicker_headerBackground * @attr ref android.R.styleable#DatePicker_headerMonthTextAppearance * @attr ref android.R.styleable#DatePicker_headerDayOfMonthTextAppearance * @attr ref android.R.styleable#DatePicker_headerYearTextAppearance diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java index 7df1fa3..eed49bf 100644 --- a/core/java/android/widget/DatePickerCalendarDelegate.java +++ b/core/java/android/widget/DatePickerCalendarDelegate.java @@ -21,7 +21,7 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.Color; +import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.text.format.DateFormat; @@ -149,16 +149,12 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i mDayOfWeekView.setTextAppearance(context, dayOfWeekTextAppearanceResId); } - final int dayOfWeekBackgroundColor = a.getColor( - R.styleable.DatePicker_dayOfWeekBackgroundColor, Color.TRANSPARENT); - mDayOfWeekView.setBackgroundColor(dayOfWeekBackgroundColor); + mDayOfWeekView.setBackground(a.getDrawable(R.styleable.DatePicker_dayOfWeekBackground)); + + dateLayout.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground)); final int headerSelectedTextColor = a.getColor( R.styleable.DatePicker_headerSelectedTextColor, defaultHighlightColor); - final int headerBackgroundColor = a.getColor(R.styleable.DatePicker_headerBackgroundColor, - Color.TRANSPARENT); - dateLayout.setBackgroundColor(headerBackgroundColor); - final int monthTextAppearanceResId = a.getResourceId( R.styleable.DatePicker_headerMonthTextAppearance, -1); if (monthTextAppearanceResId != -1) { diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 57b8dcb..033b99a 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -52,12 +52,15 @@ public class EdgeEffect { private static final String TAG = "EdgeEffect"; // Time it will take the effect to fully recede in ms - private static final int RECEDE_TIME = 1000; + private static final int RECEDE_TIME = 600; // Time it will take before a pulled glow begins receding in ms private static final int PULL_TIME = 167; - private static final float MAX_ALPHA = 1.f; + // Time it will take in ms for a pulled glow to decay to partial strength before release + private static final int PULL_DECAY_TIME = 2000; + + private static final float MAX_ALPHA = 0.5f; private static final float MAX_GLOW_SCALE = 2.f; @@ -93,12 +96,9 @@ public class EdgeEffect { private static final int STATE_RECEDE = 3; private static final int STATE_PULL_DECAY = 4; - // How much dragging should effect the height of the glow image. - // Number determined by user testing. - private static final int PULL_DISTANCE_GLOW_FACTOR = 7; - private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f; + private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f; - private static final int VELOCITY_GLOW_FACTOR = 12; + private static final int VELOCITY_GLOW_FACTOR = 6; private int mState = STATE_IDLE; @@ -107,7 +107,7 @@ public class EdgeEffect { private final Rect mBounds = new Rect(); private final Paint mPaint = new Paint(); private float mRadius; - private float mBaseGlowHeight; + private float mBaseGlowScale; private float mDisplacement = 0.5f; private float mTargetDisplacement = 0.5f; @@ -138,8 +138,12 @@ public class EdgeEffect { final float r = width * 0.75f / SIN; final float y = COS * r; final float h = r - y; + final float or = height * 0.75f / SIN; + final float oy = COS * or; + final float oh = or - oy; + mRadius = r; - mBaseGlowHeight = h; + mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f; mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h)); } @@ -319,13 +323,14 @@ public class EdgeEffect { final float centerX = mBounds.centerX(); final float centerY = mBounds.height() - mRadius; - canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0); + canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, centerX, 0); final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f; float translateX = mBounds.width() * displacement / 2; canvas.clipRect(mBounds); canvas.translate(translateX, 0); + mPaint.setAlpha((int) (0xff * mGlowAlpha)); canvas.drawCircle(centerX, centerY, mRadius, mPaint); canvas.restoreToCount(count); @@ -372,7 +377,16 @@ public class EdgeEffect { mGlowScaleYFinish = 0.f; break; case STATE_PULL: - // Hold in this state until explicitly released. + mState = STATE_PULL_DECAY; + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mDuration = PULL_DECAY_TIME; + + mGlowAlphaStart = mGlowAlpha; + mGlowScaleYStart = mGlowScaleY; + + // After pull, the glow should fade to nothing. + mGlowAlphaFinish = 0.f; + mGlowScaleYFinish = 0.f; break; case STATE_PULL_DECAY: mState = STATE_RECEDE; diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 46b225d..22138d0 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -3089,13 +3089,12 @@ public class Editor { final boolean isLeadingEdgeTopVisible = isPositionVisible(leadingEdgeX, top); final boolean isTrailingEdgeBottomVisible = isPositionVisible(trailingEdgeX, bottom); - final int characterRectFlags; - if (isLeadingEdgeTopVisible && isTrailingEdgeBottomVisible) { - characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_FULLY_VISIBLE; - } else if (isLeadingEdgeTopVisible || isTrailingEdgeBottomVisible) { - characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE; - } else { - characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_INVISIBLE; + int characterRectFlags = 0; + if (isLeadingEdgeTopVisible || isTrailingEdgeBottomVisible) { + characterRectFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; + } + if (!isLeadingEdgeTopVisible || !isTrailingEdgeBottomVisible) { + characterRectFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION; } // Here offset is the index in Java chars. // TODO: We must have a well-defined specification. For example, how @@ -3117,11 +3116,19 @@ public class Editor { + viewportToContentVerticalOffset; final float insertionMarkerBottom = layout.getLineBottom(line) + viewportToContentVerticalOffset; - // Take TextView's padding and scroll into account. - final boolean isClipped = !isPositionVisible(insertionMarkerX, insertionMarkerTop) - || !isPositionVisible(insertionMarkerX, insertionMarkerBottom); + final boolean isTopVisible = + isPositionVisible(insertionMarkerX, insertionMarkerTop); + final boolean isBottomVisible = + isPositionVisible(insertionMarkerX, insertionMarkerBottom); + int insertionMarkerFlags = 0; + if (isTopVisible || isBottomVisible) { + insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; + } + if (!isTopVisible || !isBottomVisible) { + insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION; + } builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop, - insertionMarkerBaseline, insertionMarkerBottom, isClipped); + insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags); } imm.updateCursorAnchorInfo(mTextView, builder.build()); diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index adca4cc..d2f68d0 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -458,6 +458,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { a.recycle(); setOnTouchListener(this); + setClickable(true); // Initial values final Calendar calendar = Calendar.getInstance(Locale.getDefault()); @@ -612,9 +613,9 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mMinutesTexts[i] = String.format("%02d", MINUTES_NUMBERS[i]); } - String[] amPmTexts = new DateFormatSymbols().getAmPmStrings(); - mAmPmText[AM] = amPmTexts[0]; - mAmPmText[PM] = amPmTexts[1]; + String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(mContext); + mAmPmText[AM] = amPmStrings[0]; + mAmPmText[PM] = amPmStrings[1]; } private void initData() { diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 69d5f40..90e9c69 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -22,11 +22,13 @@ import android.app.Application; import android.app.PendingIntent; import android.appwidget.AppWidgetHostView; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -1653,8 +1655,10 @@ public class RemoteViews implements Parcelable, Filter { * * @param application The application whose content is shown by the views. * @param layoutId The id of the layout resource. + * + * @hide */ - private RemoteViews(ApplicationInfo application, int layoutId) { + protected RemoteViews(ApplicationInfo application, int layoutId) { mApplication = application; mLayoutId = layoutId; mBitmapCache = new BitmapCache(); @@ -2515,15 +2519,29 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews rvToApply = getRemoteViewsToApply(context); View result; - - Context c = prepareContext(context); + // RemoteViews may be built by an application installed in another + // user. So build a context that loads resources from that user but + // still returns the current users userId so settings like data / time formats + // are loaded without requiring cross user persmissions. + final Context contextForResources = getContextForResources(context); + Context inflationContext = new ContextWrapper(context) { + @Override + public Resources getResources() { + return contextForResources.getResources(); + } + @Override + public Resources.Theme getTheme() { + return contextForResources.getTheme(); + } + }; LayoutInflater inflater = (LayoutInflater) - c.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater = inflater.cloneInContext(c); + // Clone inflater so we load resources from correct context and + // we don't add a filter to the static version returned by getSystemService. + inflater = inflater.cloneInContext(inflationContext); inflater.setFilter(this); - result = inflater.inflate(rvToApply.getLayoutId(), parent, false); rvToApply.performApply(result, parent, handler); @@ -2557,7 +2575,6 @@ public class RemoteViews implements Parcelable, Filter { } } - prepareContext(context); rvToApply.performApply(v, (ViewGroup) v.getParent(), handler); } @@ -2572,7 +2589,7 @@ public class RemoteViews implements Parcelable, Filter { } } - private Context prepareContext(Context context) { + private Context getContextForResources(Context context) { if (mApplication != null) { if (context.getUserId() == UserHandle.getUserId(mApplication.uid) && context.getPackageName().equals(mApplication.packageName)) { diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 0a3c7ff..0289ccc 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -334,6 +334,10 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { setInputType(inputType); } + boolean focusable = true; + focusable = a.getBoolean(R.styleable.SearchView_focusable, focusable); + setFocusable(focusable); + a.recycle(); // Save voice intent for later queries/launching diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 9b3a1e0..3e1b674 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1861,6 +1861,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return getCompoundPaddingTop(); } + if (mLayout == null) { + assumeLayout(); + } + if (mLayout.getLineCount() <= mMaximum) { return getCompoundPaddingTop(); } @@ -1894,6 +1898,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return getCompoundPaddingBottom(); } + if (mLayout == null) { + assumeLayout(); + } + if (mLayout.getLineCount() <= mMaximum) { return getCompoundPaddingBottom(); } diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java index 6169d2e..73e05e8 100644 --- a/core/java/android/widget/TimePickerSpinnerDelegate.java +++ b/core/java/android/widget/TimePickerSpinnerDelegate.java @@ -21,7 +21,6 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.Color; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -40,7 +39,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.R; -import java.text.DateFormatSymbols; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; @@ -71,6 +69,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im private static final int HOURS_IN_HALF_DAY = 12; + private View mHeaderView; private TextView mHourView; private TextView mMinuteView; private TextView mAmPmTextView; @@ -156,11 +155,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im mAmPmTextView.setTextAppearance(context, headerAmPmTextAppearance); } - final int headerBackgroundColor = a.getColor( - R.styleable.TimePicker_headerBackgroundColor, Color.TRANSPARENT); - if (headerBackgroundColor != Color.TRANSPARENT) { - mainView.findViewById(R.id.time_header).setBackgroundColor(headerBackgroundColor); - } + mHeaderView = mainView.findViewById(R.id.time_header); + mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground)); a.recycle(); @@ -194,14 +190,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } private void setupListeners() { - KeyboardListener keyboardListener = new KeyboardListener(); - mDelegator.setOnKeyListener(keyboardListener); + mHeaderView.setOnKeyListener(mKeyListener); + mHeaderView.setOnFocusChangeListener(mFocusListener); + mHeaderView.setFocusable(true); - mHourView.setOnKeyListener(keyboardListener); - mMinuteView.setOnKeyListener(keyboardListener); - mAmPmTextView.setOnKeyListener(keyboardListener); mRadialTimePickerView.setOnValueSelectedListener(this); - mRadialTimePickerView.setOnKeyListener(keyboardListener); mHourView.setOnClickListener(new View.OnClickListener() { @Override @@ -641,7 +634,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im if (!isTypedTimeFullyLegal()) { mTypedTimes.clear(); } - finishKbMode(true); + finishKbMode(); } } @@ -776,27 +769,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im * @return true if the key was successfully processed, false otherwise. */ private boolean processKeyUp(int keyCode) { - if (keyCode == KeyEvent.KEYCODE_ESCAPE || keyCode == KeyEvent.KEYCODE_TAB) { - if(mInKbMode) { - if (isTypedTimeFullyLegal()) { - finishKbMode(true); - } - return true; - } - } else if (keyCode == KeyEvent.KEYCODE_ENTER) { - if (mInKbMode) { - if (!isTypedTimeFullyLegal()) { - return true; - } - finishKbMode(false); - } - if (mOnTimeChangedListener != null) { - mOnTimeChangedListener.onTimeChanged(mDelegator, - mRadialTimePickerView.getCurrentHour(), - mRadialTimePickerView.getCurrentMinute()); - } - return true; - } else if (keyCode == KeyEvent.KEYCODE_DEL) { + if (keyCode == KeyEvent.KEYCODE_DEL) { if (mInKbMode) { if (!mTypedTimes.isEmpty()) { int deleted = deleteLastTypedKey(); @@ -925,9 +898,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im /** * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time. - * @param updateDisplays If true, update the displays with the relevant time. */ - private void finishKbMode(boolean updateDisplays) { + private void finishKbMode() { mInKbMode = false; if (!mTypedTimes.isEmpty()) { int values[] = getEnteredTime(null); @@ -938,10 +910,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } mTypedTimes.clear(); } - if (updateDisplays) { - updateDisplay(false); - mRadialTimePickerView.setInputEnabled(true); - } + updateDisplay(false); + mRadialTimePickerView.setInputEnabled(true); } /** @@ -1261,7 +1231,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } } - private class KeyboardListener implements View.OnKeyListener { + private final View.OnKeyListener mKeyListener = new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP) { @@ -1269,5 +1239,20 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } return false; } - } + }; + + private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) { + finishKbMode(); + + if (mOnTimeChangedListener != null) { + mOnTimeChangedListener.onTimeChanged(mDelegator, + mRadialTimePickerView.getCurrentHour(), + mRadialTimePickerView.getCurrentMinute()); + } + } + } + }; } diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index ece8aa4..be28199 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -37,6 +37,7 @@ import android.view.View; import android.view.ViewGroup; import com.android.internal.R; +import com.android.internal.app.ToolbarActionBar; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuItemImpl; import com.android.internal.view.menu.MenuPresenter; @@ -153,6 +154,8 @@ public class Toolbar extends ViewGroup { private ToolbarWidgetWrapper mWrapper; private ActionMenuPresenter mOuterActionMenuPresenter; private ExpandedActionViewMenuPresenter mExpandedMenuPresenter; + private MenuPresenter.Callback mActionMenuPresenterCallback; + private MenuBuilder.Callback mMenuBuilderCallback; private boolean mCollapsible; @@ -248,11 +251,12 @@ public class Toolbar extends ViewGroup { final Drawable navIcon = a.getDrawable(R.styleable.Toolbar_navigationIcon); if (navIcon != null) { setNavigationIcon(navIcon); - final CharSequence navDesc = a.getText( - R.styleable.Toolbar_navigationContentDescription); - if (!TextUtils.isEmpty(navDesc)) { - setNavigationContentDescription(navDesc); - } + } + + final CharSequence navDesc = a.getText( + R.styleable.Toolbar_navigationContentDescription); + if (!TextUtils.isEmpty(navDesc)) { + setNavigationContentDescription(navDesc); } a.recycle(); } @@ -824,6 +828,7 @@ public class Toolbar extends ViewGroup { mMenuView = new ActionMenuView(getContext()); mMenuView.setPopupTheme(mPopupTheme); mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener); + mMenuView.setMenuCallbacks(mActionMenuPresenterCallback, mMenuBuilderCallback); final LayoutParams lp = generateDefaultLayoutParams(); lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK); mMenuView.setLayoutParams(lp); @@ -1677,6 +1682,15 @@ public class Toolbar extends ViewGroup { } /** + * Must be called before the menu is accessed + * @hide + */ + public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) { + mActionMenuPresenterCallback = pcb; + mMenuBuilderCallback = mcb; + } + + /** * Interface responsible for receiving menu item click events if the items themselves * do not have individual item click listeners. */ diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index c409520..6d5c98e 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -63,63 +63,46 @@ public class AlertController { private final Context mContext; private final DialogInterface mDialogInterface; private final Window mWindow; - - private CharSequence mTitle; + private CharSequence mTitle; private CharSequence mMessage; - private ListView mListView; - private View mView; private int mViewLayoutResId; private int mViewSpacingLeft; - private int mViewSpacingTop; - private int mViewSpacingRight; - private int mViewSpacingBottom; - private boolean mViewSpacingSpecified = false; - - private Button mButtonPositive; + private Button mButtonPositive; private CharSequence mButtonPositiveText; - private Message mButtonPositiveMessage; private Button mButtonNegative; - private CharSequence mButtonNegativeText; - private Message mButtonNegativeMessage; private Button mButtonNeutral; - private CharSequence mButtonNeutralText; - private Message mButtonNeutralMessage; private ScrollView mScrollView; - + private int mIconId = 0; - private Drawable mIcon; - + private ImageView mIconView; - private TextView mTitleView; - private TextView mMessageView; - private View mCustomTitleView; - + private boolean mForceInverseBackground; - + private ListAdapter mAdapter; - + private int mCheckedItem = -1; private int mAlertDialogLayout; @@ -130,7 +113,7 @@ public class AlertController { private int mListItemLayout; private int mButtonPanelLayoutHint = AlertDialog.LAYOUT_HINT_NONE; - + private Handler mHandler; private final View.OnClickListener mButtonHandler = new View.OnClickListener() { @@ -160,7 +143,7 @@ public class AlertController { private static final class ButtonHandler extends Handler { // Button clicks have Message.what as the BUTTON{1,2,3} constant private static final int MSG_DISMISS_DIALOG = 1; - + private WeakReference<DialogInterface> mDialog; public ButtonHandler(DialogInterface dialog) { @@ -170,13 +153,13 @@ public class AlertController { @Override public void handleMessage(Message msg) { switch (msg.what) { - + case DialogInterface.BUTTON_POSITIVE: case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEUTRAL: ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what); break; - + case MSG_DISMISS_DIALOG: ((DialogInterface) msg.obj).dismiss(); } @@ -220,16 +203,16 @@ public class AlertController { a.recycle(); } - + static boolean canTextInput(View v) { if (v.onCheckIsTextEditor()) { return true; } - + if (!(v instanceof ViewGroup)) { return false; } - + ViewGroup vg = (ViewGroup)v; int i = vg.getChildCount(); while (i > 0) { @@ -239,10 +222,10 @@ public class AlertController { return true; } } - + return false; } - + public void installContent() { /* We use a custom title so never request a window title */ mWindow.requestFeature(Window.FEATURE_NO_TITLE); @@ -262,7 +245,7 @@ public class AlertController { // TODO: use layout hint side for long messages/lists return mAlertDialogLayout; } - + public void setTitle(CharSequence title) { mTitle = title; if (mTitleView != null) { @@ -276,7 +259,7 @@ public class AlertController { public void setCustomTitle(View customTitleView) { mCustomTitleView = customTitleView; } - + public void setMessage(CharSequence message) { mMessage = message; if (mMessageView != null) { @@ -301,7 +284,7 @@ public class AlertController { mViewLayoutResId = 0; mViewSpacingSpecified = false; } - + /** * Set the view to display in the dialog along with the spacing around that view */ @@ -326,7 +309,7 @@ public class AlertController { /** * Sets a click listener or a message to be sent when the button is clicked. * You only need to pass one of {@code listener} or {@code msg}. - * + * * @param whichButton Which button, can be one of * {@link DialogInterface#BUTTON_POSITIVE}, * {@link DialogInterface#BUTTON_NEGATIVE}, or @@ -341,24 +324,24 @@ public class AlertController { if (msg == null && listener != null) { msg = mHandler.obtainMessage(whichButton, listener); } - + switch (whichButton) { case DialogInterface.BUTTON_POSITIVE: mButtonPositiveText = text; mButtonPositiveMessage = msg; break; - + case DialogInterface.BUTTON_NEGATIVE: mButtonNegativeText = text; mButtonNegativeMessage = msg; break; - + case DialogInterface.BUTTON_NEUTRAL: mButtonNeutralText = text; mButtonNeutralMessage = msg; break; - + default: throw new IllegalArgumentException("Button does not exist"); } @@ -416,11 +399,11 @@ public class AlertController { public void setInverseBackgroundForced(boolean forceInverseBackground) { mForceInverseBackground = forceInverseBackground; } - + public ListView getListView() { return mListView; } - + public Button getButton(int whichButton) { switch (whichButton) { case DialogInterface.BUTTON_POSITIVE: @@ -433,7 +416,7 @@ public class AlertController { return null; } } - + @SuppressWarnings({"UnusedDeclaration"}) public boolean onKeyDown(int keyCode, KeyEvent event) { return mScrollView != null && mScrollView.executeKeyEvent(event); @@ -469,12 +452,12 @@ public class AlertController { final LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel); setupContent(contentPanel); final boolean hasButtons = setupButtons(); - + final LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel); final TypedArray a = mContext.obtainStyledAttributes( null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0); final boolean hasTitle = setupTitle(topPanel); - + final View buttonPanel = mWindow.findViewById(R.id.buttonPanel); if (!hasButtons) { buttonPanel.setVisibility(View.GONE); @@ -536,14 +519,14 @@ public class AlertController { private boolean setupTitle(LinearLayout topPanel) { boolean hasTitle = true; - + if (mCustomTitleView != null) { // Add the custom title view directly to the topPanel layout LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - + topPanel.addView(mCustomTitleView, 0, lp); - + // Hide the title template View titleTemplate = mWindow.findViewById(R.id.title_template); titleTemplate.setVisibility(View.GONE); @@ -587,19 +570,19 @@ public class AlertController { private void setupContent(LinearLayout contentPanel) { mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView); mScrollView.setFocusable(false); - + // Special case for users that only want to display a String mMessageView = (TextView) mWindow.findViewById(R.id.message); if (mMessageView == null) { return; } - + if (mMessage != null) { mMessageView.setText(mMessage); } else { mMessageView.setVisibility(View.GONE); mScrollView.removeView(mMessageView); - + if (mListView != null) { contentPanel.removeView(mWindow.findViewById(R.id.scrollView)); contentPanel.addView(mListView, @@ -664,7 +647,7 @@ public class AlertController { centerButton(mButtonNeutral); } } - + return whichButtons != 0; } @@ -694,7 +677,12 @@ public class AlertController { int centerBright = 0; int bottomBright = 0; int bottomMedium = 0; - if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.KITKAT) { + + // If the needsDefaultBackgrounds attribute is set, we know we're + // inheriting from a framework style. + final boolean needsDefaultBackgrounds = a.getBoolean( + R.styleable.AlertDialog_needsDefaultBackgrounds, true); + if (needsDefaultBackgrounds) { fullDark = R.drawable.popup_full_dark; topDark = R.drawable.popup_top_dark; centerDark = R.drawable.popup_center_dark; @@ -705,12 +693,12 @@ public class AlertController { bottomBright = R.drawable.popup_bottom_bright; bottomMedium = R.drawable.popup_bottom_medium; } + topBright = a.getResourceId(R.styleable.AlertDialog_topBright, topBright); topDark = a.getResourceId(R.styleable.AlertDialog_topDark, topDark); centerBright = a.getResourceId(R.styleable.AlertDialog_centerBright, centerBright); centerDark = a.getResourceId(R.styleable.AlertDialog_centerDark, centerDark); - /* We now set the background of all of the sections of the alert. * First collect together each section that is being displayed along * with whether it is on a light or dark background, then run through @@ -789,31 +777,6 @@ public class AlertController { } } - /* TODO: uncomment section below. The logic for this should be if - * it's a Contextual menu being displayed AND only a Cancel button - * is shown then do this. - */ -// if (hasButtons && (mListView != null)) { - - /* Yet another *special* case. If there is a ListView with buttons - * don't put the buttons on the bottom but instead put them in the - * footer of the ListView this will allow more items to be - * displayed. - */ - - /* - contentPanel.setBackgroundResource(bottomBright); - buttonPanel.setBackgroundResource(centerMedium); - ViewGroup parent = (ViewGroup) mWindow.findViewById(R.id.parentPanel); - parent.removeView(buttonPanel); - AbsListView.LayoutParams params = new AbsListView.LayoutParams( - AbsListView.LayoutParams.MATCH_PARENT, - AbsListView.LayoutParams.MATCH_PARENT); - buttonPanel.setLayoutParams(params); - mListView.addFooterView(buttonPanel); - */ -// } - final ListView listView = mListView; if (listView != null && mAdapter != null) { listView.setAdapter(mAdapter); @@ -854,7 +817,7 @@ public class AlertController { public static class AlertParams { public final Context mContext; public final LayoutInflater mInflater; - + public int mIconId = 0; public Drawable mIcon; public int mIconAttrId = 0; @@ -899,20 +862,20 @@ public class AlertController { * will be bound to an adapter. */ public interface OnPrepareListViewListener { - + /** * Called before the ListView is bound to an adapter. * @param listView The ListView that will be shown in the dialog. */ void onPrepareListView(ListView listView); } - + public AlertParams(Context context) { mContext = context; mCancelable = true; mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } - + public void apply(AlertController dialog) { if (mCustomTitleView != null) { dialog.setCustomTitle(mCustomTitleView); @@ -972,12 +935,12 @@ public class AlertController { } */ } - + private void createListView(final AlertController dialog) { final RecycleListView listView = (RecycleListView) mInflater.inflate(dialog.mListLayout, null); ListAdapter adapter; - + if (mIsMultiChoice) { if (mCursor == null) { adapter = new ArrayAdapter<CharSequence>( @@ -1012,37 +975,37 @@ public class AlertController { listView.setItemChecked(cursor.getPosition(), cursor.getInt(mIsCheckedIndex) == 1); } - + @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return mInflater.inflate(dialog.mMultiChoiceItemLayout, parent, false); } - + }; } } else { - int layout = mIsSingleChoice + int layout = mIsSingleChoice ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout; if (mCursor == null) { adapter = (mAdapter != null) ? mAdapter : new CheckedItemAdapter(mContext, layout, R.id.text1, mItems); } else { - adapter = new SimpleCursorAdapter(mContext, layout, + adapter = new SimpleCursorAdapter(mContext, layout, mCursor, new String[]{mLabelColumn}, new int[]{R.id.text1}); } } - + if (mOnPrepareListViewListener != null) { mOnPrepareListViewListener.onPrepareListView(listView); } - + /* Don't directly set the adapter on the ListView as we might * want to add a footer to the ListView later. */ dialog.mAdapter = adapter; dialog.mCheckedItem = mCheckedItem; - + if (mOnClickListener != null) { listView.setOnItemClickListener(new OnItemClickListener() { @Override @@ -1065,12 +1028,12 @@ public class AlertController { } }); } - + // Attach a given OnItemSelectedListener to the ListView if (mOnItemSelectedListener != null) { listView.setOnItemSelectedListener(mOnItemSelectedListener); } - + if (mIsSingleChoice) { listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); } else if (mIsMultiChoice) { diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java index abe8a9f..99c87ea 100644 --- a/core/java/com/android/internal/app/ToolbarActionBar.java +++ b/core/java/com/android/internal/app/ToolbarActionBar.java @@ -22,6 +22,7 @@ import android.app.ActionBar; import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import android.view.ActionMode; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -32,7 +33,9 @@ import android.view.Window; import android.view.WindowCallbackWrapper; import android.widget.SpinnerAdapter; import android.widget.Toolbar; +import com.android.internal.R; import com.android.internal.view.menu.MenuBuilder; +import com.android.internal.view.menu.MenuPresenter; import com.android.internal.widget.DecorToolbar; import com.android.internal.widget.ToolbarWidgetWrapper; @@ -43,6 +46,9 @@ public class ToolbarActionBar extends ActionBar { private DecorToolbar mDecorToolbar; private boolean mToolbarMenuPrepared; private Window.Callback mWindowCallback; + private boolean mMenuCallbackSet; + + private CharSequence mHomeDescription; private boolean mLastMenuVisibility; private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners = @@ -70,6 +76,8 @@ public class ToolbarActionBar extends ActionBar { mDecorToolbar.setWindowCallback(mWindowCallback); toolbar.setOnMenuItemClickListener(mMenuClicker); mDecorToolbar.setWindowTitle(title); + mHomeDescription = mToolbar.getNavigationContentDescription(); + updateNavDescription(); } public Window.Callback getWrappedWindowCallback() { @@ -161,6 +169,7 @@ public class ToolbarActionBar extends ActionBar { @Override public void setHomeActionContentDescription(CharSequence description) { mToolbar.setNavigationContentDescription(description); + mHomeDescription = description; } @Override @@ -171,6 +180,7 @@ public class ToolbarActionBar extends ActionBar { @Override public void setHomeActionContentDescription(int resId) { mToolbar.setNavigationContentDescription(resId); + mHomeDescription = mToolbar.getNavigationContentDescription(); } @Override @@ -247,8 +257,22 @@ public class ToolbarActionBar extends ActionBar { @Override public void setDisplayOptions(@DisplayOptions int options, @DisplayOptions int mask) { - mDecorToolbar.setDisplayOptions((options & mask) | - mDecorToolbar.getDisplayOptions() & ~mask); + final int currentOptions = mDecorToolbar.getDisplayOptions(); + final int changed = (options ^ currentOptions) & mask; + mDecorToolbar.setDisplayOptions(options & mask | currentOptions & ~mask); + if ((changed & ActionBar.DISPLAY_HOME_AS_UP) != 0) { + updateNavDescription(); + } + } + + private void updateNavDescription() { + if ((mDecorToolbar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) { + if (TextUtils.isEmpty(mHomeDescription)) { + mToolbar.setNavigationContentDescription(R.string.action_bar_up_description); + } else { + mToolbar.setNavigationContentDescription(mHomeDescription); + } + } } @Override @@ -431,6 +455,10 @@ public class ToolbarActionBar extends ActionBar { } void populateOptionsMenu() { + if (!mMenuCallbackSet) { + mToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback()); + mMenuCallbackSet = true; + } final Menu menu = mToolbar.getMenu(); final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null; if (mb != null) { @@ -492,4 +520,51 @@ public class ToolbarActionBar extends ActionBar { return result; } } + + private final class ActionMenuPresenterCallback implements MenuPresenter.Callback { + private boolean mClosingActionMenu; + + @Override + public boolean onOpenSubMenu(MenuBuilder subMenu) { + if (mWindowCallback != null) { + mWindowCallback.onMenuOpened(Window.FEATURE_ACTION_BAR, subMenu); + return true; + } + return false; + } + + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + if (mClosingActionMenu) { + return; + } + + mClosingActionMenu = true; + mToolbar.dismissPopupMenus(); + if (mWindowCallback != null) { + mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu); + } + mClosingActionMenu = false; + } + } + + private final class MenuBuilderCallback implements MenuBuilder.Callback { + + @Override + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + return false; + } + + @Override + public void onMenuModeChange(MenuBuilder menu) { + if (mWindowCallback != null) { + if (mToolbar.isOverflowMenuShowing()) { + mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu); + } else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, + null, menu)) { + mWindowCallback.onMenuOpened(Window.FEATURE_ACTION_BAR, menu); + } + } + } + } } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 54c532a..c5211bb 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -20,9 +20,12 @@ package com.android.internal.os; import dalvik.system.ZygoteHooks; import android.system.ErrnoException; import android.system.Os; +import android.os.SystemClock; +import android.util.Slog; /** @hide */ public final class Zygote { + private static final String TAG = "Zygote"; /* * Bit values for "debugFlags" argument. The definitions are duplicated * in the native code. @@ -81,10 +84,14 @@ public final class Zygote { */ public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose) { + long startTime = SystemClock.elapsedRealtime(); VM_HOOKS.preFork(); + checkTime(startTime, "Zygote.preFork"); int pid = nativeForkAndSpecialize( uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose); + checkTime(startTime, "Zygote.nativeForkAndSpecialize"); VM_HOOKS.postForkCommon(); + checkTime(startTime, "Zygote.postForkCommon"); return pid; } @@ -92,6 +99,18 @@ public final class Zygote { int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose); /** + * Temporary hack: check time since start time and log if over a fixed threshold. + * + */ + private static void checkTime(long startTime, String where) { + long now = SystemClock.elapsedRealtime(); + if ((now-startTime) > 1000) { + // If we are taking more than a second, log about it. + Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where); + } + } + + /** * Special method to start the system server process. In addition to the * common actions performed in forkAndSpecialize, the pid of the child * process is recorded such that the death of the child process will cause @@ -127,7 +146,9 @@ public final class Zygote { int[][] rlimits, long permittedCapabilities, long effectiveCapabilities); private static void callPostForkChildHooks(int debugFlags) { + long startTime = SystemClock.elapsedRealtime(); VM_HOOKS.postForkChild(debugFlags); + checkTime(startTime, "Zygote.callPostForkChildHooks"); } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 43ebb3d..b4c4da6 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -37,6 +37,8 @@ import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import libcore.io.IoUtils; +import android.os.SystemClock; +import android.util.Slog; /** * A connection that can make spawn requests. @@ -103,11 +105,23 @@ class ZygoteConnection { } /** + * Temporary hack: check time since start time and log if over a fixed threshold. + * + */ + private void checkTime(long startTime, String where) { + long now = SystemClock.elapsedRealtime(); + if ((now-startTime) > 1000) { + // If we are taking more than a second, log about it. + Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where); + } + } + + /** * Returns the file descriptor of the associated socket. * * @return null-ok; file descriptor */ - FileDescriptor getFileDesciptor() { + FileDescriptor getFileDescriptor() { return mSocket.getFileDescriptor(); } @@ -131,6 +145,8 @@ class ZygoteConnection { Arguments parsedArgs = null; FileDescriptor[] descriptors; + long startTime = SystemClock.elapsedRealtime(); + try { args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); @@ -140,6 +156,7 @@ class ZygoteConnection { return true; } + checkTime(startTime, "zygoteConnection.runOnce: readArgumentList"); if (args == null) { // EOF reached. closeSocket(); @@ -171,14 +188,19 @@ class ZygoteConnection { ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities)); } + applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); + checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); + applyDebuggerSystemProperty(parsedArgs); applyInvokeWithSystemProperty(parsedArgs); + checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); + int[][] rlimits = null; if (parsedArgs.rlimits != null) { @@ -220,9 +242,11 @@ class ZygoteConnection { fd = null; + checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize"); pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose); + checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize"); } catch (IOException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (ErrnoException ex) { diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 051de6e..0aee0e3 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -770,7 +770,7 @@ public class ZygoteInit { } else if (index == 0) { ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); - fds.add(newPeer.getFileDesciptor()); + fds.add(newPeer.getFileDescriptor()); } else { boolean done; done = peers.get(index).runOnce(); diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java index a5ce6e0..c153904 100644 --- a/core/java/com/android/internal/util/ImageUtils.java +++ b/core/java/com/android/internal/util/ImageUtils.java @@ -17,6 +17,10 @@ package com.android.internal.util; import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; /** * Utility class for image analysis and processing. @@ -31,17 +35,49 @@ public class ImageUtils { // Alpha amount for which values below are considered transparent. private static final int ALPHA_TOLERANCE = 50; + // Size of the smaller bitmap we're actually going to scan. + private static final int COMPACT_BITMAP_SIZE = 64; // pixels + private int[] mTempBuffer; + private Bitmap mTempCompactBitmap; + private Canvas mTempCompactBitmapCanvas; + private Paint mTempCompactBitmapPaint; + private final Matrix mTempMatrix = new Matrix(); /** * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect * gray". + * + * Instead of scanning every pixel in the bitmap, we first resize the bitmap to no more than + * COMPACT_BITMAP_SIZE^2 pixels using filtering. The hope is that any non-gray color elements + * will survive the squeezing process, contaminating the result with color. */ public boolean isGrayscale(Bitmap bitmap) { - final int height = bitmap.getHeight(); - final int width = bitmap.getWidth(); - int size = height*width; + int height = bitmap.getHeight(); + int width = bitmap.getWidth(); + + // shrink to a more manageable (yet hopefully no more or less colorful) size + if (height > COMPACT_BITMAP_SIZE || width > COMPACT_BITMAP_SIZE) { + if (mTempCompactBitmap == null) { + mTempCompactBitmap = Bitmap.createBitmap( + COMPACT_BITMAP_SIZE, COMPACT_BITMAP_SIZE, Bitmap.Config.ARGB_8888 + ); + mTempCompactBitmapCanvas = new Canvas(mTempCompactBitmap); + mTempCompactBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTempCompactBitmapPaint.setFilterBitmap(true); + } + mTempMatrix.reset(); + mTempMatrix.setScale( + (float) COMPACT_BITMAP_SIZE / width, + (float) COMPACT_BITMAP_SIZE / height, + 0, 0); + mTempCompactBitmapCanvas.drawColor(0, PorterDuff.Mode.SRC); // select all, erase + mTempCompactBitmapCanvas.drawBitmap(bitmap, mTempMatrix, mTempCompactBitmapPaint); + bitmap = mTempCompactBitmap; + width = height = COMPACT_BITMAP_SIZE; + } + final int size = height*width; ensureBufferSize(size); bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height); for (int i = 0; i < size; i++) { diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java index 665055c..3249ea3 100644 --- a/core/java/com/android/internal/util/NotificationColorUtil.java +++ b/core/java/com/android/internal/util/NotificationColorUtil.java @@ -50,23 +50,36 @@ public class NotificationColorUtil { private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache = new WeakHashMap<Bitmap, Pair<Boolean, Integer>>(); - public static NotificationColorUtil getInstance() { + private final int mGrayscaleIconMaxSize; // @dimen/notification_large_icon_width (64dp) + + public static NotificationColorUtil getInstance(Context context) { synchronized (sLock) { if (sInstance == null) { - sInstance = new NotificationColorUtil(); + sInstance = new NotificationColorUtil(context); } return sInstance; } } + private NotificationColorUtil(Context context) { + mGrayscaleIconMaxSize = context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.notification_large_icon_width); + } + /** - * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect - * gray". + * Checks whether a Bitmap is a small grayscale icon. + * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param bitmap The bitmap to test. - * @return Whether the bitmap is grayscale. + * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ - public boolean isGrayscale(Bitmap bitmap) { + public boolean isGrayscaleIcon(Bitmap bitmap) { + // quick test: reject large bitmaps + if (bitmap.getWidth() > mGrayscaleIconMaxSize + || bitmap.getHeight() > mGrayscaleIconMaxSize) { + return false; + } + synchronized (sLock) { Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap); if (cached != null) { @@ -92,22 +105,22 @@ public class NotificationColorUtil { } /** - * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect - * gray". + * Checks whether a Drawable is a small grayscale icon. + * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param d The drawable to test. - * @return Whether the drawable is grayscale. + * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ - public boolean isGrayscale(Drawable d) { + public boolean isGrayscaleIcon(Drawable d) { if (d == null) { return false; } else if (d instanceof BitmapDrawable) { BitmapDrawable bd = (BitmapDrawable) d; - return bd.getBitmap() != null && isGrayscale(bd.getBitmap()); + return bd.getBitmap() != null && isGrayscaleIcon(bd.getBitmap()); } else if (d instanceof AnimationDrawable) { AnimationDrawable ad = (AnimationDrawable) d; int count = ad.getNumberOfFrames(); - return count > 0 && isGrayscale(ad.getFrame(0)); + return count > 0 && isGrayscaleIcon(ad.getFrame(0)); } else if (d instanceof VectorDrawable) { // We just assume you're doing the right thing if using vectors return true; @@ -117,16 +130,16 @@ public class NotificationColorUtil { } /** - * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close - * to a perfect gray". + * Checks whether a drawable with a resoure id is a small grayscale icon. + * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param context The context to load the drawable from. - * @return Whether the drawable is grayscale. + * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ - public boolean isGrayscale(Context context, int drawableResId) { + public boolean isGrayscaleIcon(Context context, int drawableResId) { if (drawableResId != 0) { try { - return isGrayscale(context.getDrawable(drawableResId)); + return isGrayscaleIcon(context.getDrawable(drawableResId)); } catch (Resources.NotFoundException ex) { Log.e(TAG, "Drawable not found: " + drawableResId); return false; diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java index b1f5d90..e19b2b6 100644 --- a/core/java/com/android/internal/view/IInputConnectionWrapper.java +++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java @@ -437,7 +437,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub { return; } args.callback.setRequestUpdateCursorAnchorInfoResult( - ic.requestUpdateCursorAnchorInfo(msg.arg1), args.seq); + ic.requestCursorUpdates(msg.arg1), args.seq); } catch (RemoteException e) { Log.w(TAG, "Got RemoteException calling requestCursorAnchorInfo", e); } diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java index a8526c8..0c65ad1 100644 --- a/core/java/com/android/internal/view/InputConnectionWrapper.java +++ b/core/java/com/android/internal/view/InputConnectionWrapper.java @@ -428,7 +428,7 @@ public class InputConnectionWrapper implements InputConnection { } } - public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + public boolean requestCursorUpdates(int cursorUpdateMode) { boolean result = false; try { InputContextCallback callback = InputContextCallback.getInstance(); @@ -445,4 +445,11 @@ public class InputConnectionWrapper implements InputConnection { } return result; } + + /** + * @removed + */ + public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + return requestCursorUpdates(cursorUpdateMode); + } } diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java index c7ac815..062a9b1 100644 --- a/core/java/com/android/internal/widget/ActionBarContextView.java +++ b/core/java/com/android/internal/widget/ActionBarContextView.java @@ -59,6 +59,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi private int mSubtitleStyleRes; private Drawable mSplitBackground; private boolean mTitleOptional; + private int mCloseItemLayout; private Animator mCurrentAnimation; private boolean mAnimateInOnLayout; @@ -99,6 +100,10 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi mSplitBackground = a.getDrawable( com.android.internal.R.styleable.ActionMode_backgroundSplit); + mCloseItemLayout = a.getResourceId( + com.android.internal.R.styleable.ActionMode_closeItemLayout, + R.layout.action_mode_close_item); + a.recycle(); } @@ -120,7 +125,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi LayoutParams.MATCH_PARENT); if (!split) { mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); - mMenuView.setBackgroundDrawable(null); + mMenuView.setBackground(null); final ViewGroup oldParent = (ViewGroup) mMenuView.getParent(); if (oldParent != null) oldParent.removeView(mMenuView); addView(mMenuView, layoutParams); @@ -134,7 +139,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi layoutParams.width = LayoutParams.MATCH_PARENT; layoutParams.height = mContentHeight; mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); - mMenuView.setBackgroundDrawable(mSplitBackground); + mMenuView.setBackground(mSplitBackground); final ViewGroup oldParent = (ViewGroup) mMenuView.getParent(); if (oldParent != null) oldParent.removeView(mMenuView); mSplitView.addView(mMenuView, layoutParams); @@ -211,7 +216,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi public void initForMode(final ActionMode mode) { if (mClose == null) { LayoutInflater inflater = LayoutInflater.from(mContext); - mClose = inflater.inflate(R.layout.action_mode_close_item, this, false); + mClose = inflater.inflate(mCloseItemLayout, this, false); addView(mClose); } else if (mClose.getParent() == null) { addView(mClose); diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java index ba236f3..f211ff2 100644 --- a/core/java/com/android/internal/widget/EditableInputConnection.java +++ b/core/java/com/android/internal/widget/EditableInputConnection.java @@ -188,13 +188,13 @@ public class EditableInputConnection extends BaseInputConnection { } @Override - public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) { + public boolean requestCursorUpdates(int cursorUpdateMode) { if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode); // It is possible that any other bit is used as a valid flag in a future release. // We should reject the entire request in such a case. - final int KNOWN_FLAGS_MASK = InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE | - InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR; + final int KNOWN_FLAGS_MASK = InputConnection.CURSOR_UPDATE_IMMEDIATE | + InputConnection.CURSOR_UPDATE_MONITOR; final int unknownFlags = cursorUpdateMode & ~KNOWN_FLAGS_MASK; if (unknownFlags != 0) { if (DEBUG) { @@ -212,7 +212,7 @@ public class EditableInputConnection extends BaseInputConnection { return false; } mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode); - if ((cursorUpdateMode & InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0) { + if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) { if (mTextView == null) { // In this case, FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is silently ignored. // TODO: Return some notification code for the input method that indicates diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 2114ff6..c84708e 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1449,7 +1449,7 @@ public class LockPatternUtils { } int textId; - if (getTelecommManager().isInCall()) { + if (isInCall()) { // show "return to call" text and show phone icon textId = R.string.lockscreen_return_to_call; int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0; @@ -1470,6 +1470,13 @@ public class LockPatternUtils { getTelecommManager().showInCallScreen(false); } + /** + * @return {@code true} if there is a call currently in progress, {@code false} otherwise. + */ + public boolean isInCall() { + return getTelecommManager().isInCall(); + } + private TelecommManager getTelecommManager() { return (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE); } diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 62ea351..8ea28ec 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -367,6 +367,9 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding peeker.mOpticalInsets[0], peeker.mOpticalInsets[1], peeker.mOpticalInsets[2], peeker.mOpticalInsets[3], peeker.mOutlineInsets[0], peeker.mOutlineInsets[1], peeker.mOutlineInsets[2], peeker.mOutlineInsets[3], peeker.mOutlineRadius, peeker.mOutlineAlpha, scale); + if (ninePatchInsets == NULL) { + return nullObjectReturn("nine patch insets == null"); + } if (javaBitmap != NULL) { env->SetObjectField(javaBitmap, gBitmap_ninePatchInsetsFieldID, ninePatchInsets); } diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 7c41c2e..d7b75db 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -419,6 +419,7 @@ jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buff { SkASSERT(bitmap); SkASSERT(bitmap->pixelRef()); + SkASSERT(!env->ExceptionCheck()); bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable; bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied; diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 1296831..949f4ff 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -458,7 +458,7 @@ static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz, static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->animators().endAllAnimators(); + renderNode->animators().endAllStagingAnimators(); } #endif // USE_OPENGL_RENDERER diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 99babac..7e6d335 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -166,12 +166,7 @@ public: // Runs any animations still left in mCurrentFrameAnimations virtual void runRemainingAnimations(TreeInfo& info) { AnimationContext::runRemainingAnimations(info); - // post all the finished stuff - if (mOnFinishedEvents.size()) { - sp<InvokeAnimationListeners> message - = new InvokeAnimationListeners(mOnFinishedEvents); - mRootNode->sendMessage(message); - } + postOnFinishedEvents(); } virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) { @@ -179,9 +174,22 @@ public: mOnFinishedEvents.push_back(event); } + virtual void destroy() { + AnimationContext::destroy(); + postOnFinishedEvents(); + } + private: sp<RootRenderNode> mRootNode; std::vector<OnFinishedEvent> mOnFinishedEvents; + + void postOnFinishedEvents() { + if (mOnFinishedEvents.size()) { + sp<InvokeAnimationListeners> message + = new InvokeAnimationListeners(mOnFinishedEvents); + mRootNode->sendMessage(message); + } + } }; class ContextFactoryImpl : public IContextFactory { @@ -291,10 +299,10 @@ static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject c return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density); } -static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz, +static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz, jlong proxyPtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - proxy->destroyCanvasAndSurface(); + proxy->destroy(); } static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz, @@ -430,7 +438,7 @@ static JNINativeMethod gMethods[] = { { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup }, { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque }, { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, - { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface }, + { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy }, { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode }, { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer }, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 1f7acec..3d2d471 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -43,6 +43,7 @@ #include <utils/String8.h> #include <selinux/android.h> #include <processgroup/processgroup.h> +#include <inttypes.h> #include "android_runtime/AndroidRuntime.h" #include "JNIHelp.h" @@ -398,6 +399,22 @@ void SetThreadName(const char* thread_name) { } } + // Temporary timing check. +uint64_t MsTime() { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000); +} + + +void ckTime(uint64_t start, const char* where) { + uint64_t now = MsTime(); + if ((now-start) > 1000) { + // If we are taking more than a second, log about it. + ALOGW("Slow operation: %"PRIu64" ms in %s", (uint64_t)(now-start), where); + } +} + // Utility routine to fork zygote and specialize the child process. static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, jint debug_flags, jobjectArray javaRlimits, @@ -405,7 +422,9 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose) { + uint64_t start = MsTime(); SetSigChldHandler(); + ckTime(start, "ForkAndSpecializeCommon:SetSigChldHandler"); pid_t pid = fork(); @@ -413,9 +432,12 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra // The child process. gMallocLeakZygoteChild = 1; + // Clean up any descriptors which must be closed immediately DetachDescriptors(env, fdsToClose); + ckTime(start, "ForkAndSpecializeCommon:Fork and detach"); + // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { EnableKeepCapabilities(env); @@ -518,7 +540,10 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra UnsetSigChldHandler(); + ckTime(start, "ForkAndSpecializeCommon:child process setup"); + env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags); + ckTime(start, "ForkAndSpecializeCommon:PostForkChildHooks returns"); if (env->ExceptionCheck()) { ALOGE("Error calling post fork hooks."); RuntimeAbort(env); diff --git a/core/res/res/drawable-hdpi/pointer_arrow_icon.xml b/core/res/res/drawable-hdpi/pointer_arrow_icon.xml deleted file mode 100644 index a4cce5c..0000000 --- a/core/res/res/drawable-hdpi/pointer_arrow_icon.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" - android:bitmap="@drawable/pointer_arrow" - android:hotSpotX="9" - android:hotSpotY="9" /> diff --git a/core/res/res/drawable-hdpi/pointer_spot_anchor.png b/core/res/res/drawable-hdpi/pointer_spot_anchor.png Binary files differindex d7aca36..bdb5311 100644 --- a/core/res/res/drawable-hdpi/pointer_spot_anchor.png +++ b/core/res/res/drawable-hdpi/pointer_spot_anchor.png diff --git a/core/res/res/drawable-hdpi/pointer_spot_anchor_icon.xml b/core/res/res/drawable-hdpi/pointer_spot_anchor_icon.xml deleted file mode 100644 index 2222b8e..0000000 --- a/core/res/res/drawable-hdpi/pointer_spot_anchor_icon.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" - android:bitmap="@drawable/pointer_spot_anchor" - android:hotSpotX="33" - android:hotSpotY="33" /> diff --git a/core/res/res/drawable-hdpi/pointer_spot_hover.png b/core/res/res/drawable-hdpi/pointer_spot_hover.png Binary files differindex 5041aa3..e7f2a0c 100644 --- a/core/res/res/drawable-hdpi/pointer_spot_hover.png +++ b/core/res/res/drawable-hdpi/pointer_spot_hover.png diff --git a/core/res/res/drawable-hdpi/pointer_spot_hover_icon.xml b/core/res/res/drawable-hdpi/pointer_spot_hover_icon.xml deleted file mode 100644 index dc62a69..0000000 --- a/core/res/res/drawable-hdpi/pointer_spot_hover_icon.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" - android:bitmap="@drawable/pointer_spot_hover" - android:hotSpotX="33" - android:hotSpotY="33" /> diff --git a/core/res/res/drawable-hdpi/pointer_spot_touch.png b/core/res/res/drawable-hdpi/pointer_spot_touch.png Binary files differindex 64a42a1..0326f91 100644 --- a/core/res/res/drawable-hdpi/pointer_spot_touch.png +++ b/core/res/res/drawable-hdpi/pointer_spot_touch.png diff --git a/core/res/res/drawable-mdpi/pointer_arrow_icon.xml b/core/res/res/drawable-mdpi/pointer_arrow_icon.xml deleted file mode 100644 index 2f5676f..0000000 --- a/core/res/res/drawable-mdpi/pointer_arrow_icon.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" - android:bitmap="@drawable/pointer_arrow" - android:hotSpotX="6" - android:hotSpotY="6" /> diff --git a/core/res/res/drawable-mdpi/pointer_spot_anchor.png b/core/res/res/drawable-mdpi/pointer_spot_anchor.png Binary files differindex d7aca36..4e282e7 100644 --- a/core/res/res/drawable-mdpi/pointer_spot_anchor.png +++ b/core/res/res/drawable-mdpi/pointer_spot_anchor.png diff --git a/core/res/res/drawable-mdpi/pointer_spot_hover.png b/core/res/res/drawable-mdpi/pointer_spot_hover.png Binary files differindex 5041aa3..67d0b06 100644 --- a/core/res/res/drawable-mdpi/pointer_spot_hover.png +++ b/core/res/res/drawable-mdpi/pointer_spot_hover.png diff --git a/core/res/res/drawable-mdpi/pointer_spot_touch.png b/core/res/res/drawable-mdpi/pointer_spot_touch.png Binary files differindex 64a42a1..45dc5c0 100644 --- a/core/res/res/drawable-mdpi/pointer_spot_touch.png +++ b/core/res/res/drawable-mdpi/pointer_spot_touch.png diff --git a/core/res/res/drawable-mdpi/pointer_spot_touch_icon.xml b/core/res/res/drawable-mdpi/pointer_spot_touch_icon.xml deleted file mode 100644 index 4bffee6..0000000 --- a/core/res/res/drawable-mdpi/pointer_spot_touch_icon.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" - android:bitmap="@drawable/pointer_spot_touch" - android:hotSpotX="24" - android:hotSpotY="24" /> diff --git a/core/res/res/drawable-xhdpi/pointer_spot_anchor.png b/core/res/res/drawable-xhdpi/pointer_spot_anchor.png Binary files differindex ad41c97..fa9226e 100644 --- a/core/res/res/drawable-xhdpi/pointer_spot_anchor.png +++ b/core/res/res/drawable-xhdpi/pointer_spot_anchor.png diff --git a/core/res/res/drawable-xhdpi/pointer_spot_hover.png b/core/res/res/drawable-xhdpi/pointer_spot_hover.png Binary files differindex e9b98f6..f09a778 100644 --- a/core/res/res/drawable-xhdpi/pointer_spot_hover.png +++ b/core/res/res/drawable-xhdpi/pointer_spot_hover.png diff --git a/core/res/res/drawable-xhdpi/pointer_spot_touch.png b/core/res/res/drawable-xhdpi/pointer_spot_touch.png Binary files differindex e10d998..53d7a20 100644 --- a/core/res/res/drawable-xhdpi/pointer_spot_touch.png +++ b/core/res/res/drawable-xhdpi/pointer_spot_touch.png diff --git a/core/res/res/drawable-xhdpi/pointer_arrow_icon.xml b/core/res/res/drawable/pointer_arrow_icon.xml index 2fbe45a..8f7d658 100644 --- a/core/res/res/drawable-xhdpi/pointer_arrow_icon.xml +++ b/core/res/res/drawable/pointer_arrow_icon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" android:bitmap="@drawable/pointer_arrow" - android:hotSpotX="12" - android:hotSpotY="12" /> + android:hotSpotX="6dp" + android:hotSpotY="6dp" /> diff --git a/core/res/res/drawable-mdpi/pointer_spot_anchor_icon.xml b/core/res/res/drawable/pointer_spot_anchor_icon.xml index 2222b8e..73c0c11 100644 --- a/core/res/res/drawable-mdpi/pointer_spot_anchor_icon.xml +++ b/core/res/res/drawable/pointer_spot_anchor_icon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" android:bitmap="@drawable/pointer_spot_anchor" - android:hotSpotX="33" - android:hotSpotY="33" /> + android:hotSpotX="22dp" + android:hotSpotY="22dp" /> diff --git a/core/res/res/drawable-mdpi/pointer_spot_hover_icon.xml b/core/res/res/drawable/pointer_spot_hover_icon.xml index dc62a69..1d7440b 100644 --- a/core/res/res/drawable-mdpi/pointer_spot_hover_icon.xml +++ b/core/res/res/drawable/pointer_spot_hover_icon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" android:bitmap="@drawable/pointer_spot_hover" - android:hotSpotX="33" - android:hotSpotY="33" /> + android:hotSpotX="22dp" + android:hotSpotY="22dp" /> diff --git a/core/res/res/drawable-hdpi/pointer_spot_touch_icon.xml b/core/res/res/drawable/pointer_spot_touch_icon.xml index 4bffee6..f4f0639 100644 --- a/core/res/res/drawable-hdpi/pointer_spot_touch_icon.xml +++ b/core/res/res/drawable/pointer_spot_touch_icon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" android:bitmap="@drawable/pointer_spot_touch" - android:hotSpotX="24" - android:hotSpotY="24" /> + android:hotSpotX="16dp" + android:hotSpotY="16dp" /> diff --git a/core/res/res/drawable/stat_sys_tether_wifi.xml b/core/res/res/drawable/stat_sys_tether_wifi.xml index a816db8..4396962 100644 --- a/core/res/res/drawable/stat_sys_tether_wifi.xml +++ b/core/res/res/drawable/stat_sys_tether_wifi.xml @@ -14,11 +14,12 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="26.0dp" + android:width="24.0dp" android:height="24.0dp" - android:viewportWidth="26.0" - android:viewportHeight="24.0"> + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + <path android:fillColor="#FFFFFFFF" - android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/> + android:pathData="M24.000000,22.000000c-2.200000,0.000000 -4.000000,1.800000 -4.000000,4.000000c0.000000,2.200000 1.800000,4.000000 4.000000,4.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000C28.000000,23.799999 26.200001,22.000000 24.000000,22.000000zM36.000000,26.000000c0.000000,-6.600000 -5.400000,-12.000000 -12.000000,-12.000000c-6.600000,0.000000 -12.000000,5.400000 -12.000000,12.000000c0.000000,4.400000 2.400000,8.300000 6.000000,10.400000l2.000000,-3.500000c-2.400000,-1.400000 -4.000000,-3.900000 -4.000000,-6.900000c0.000000,-4.400000 3.600000,-8.000000 8.000000,-8.000000s8.000000,3.600000 8.000000,8.000000c0.000000,3.000000 -1.600000,5.500000 -4.000000,6.900000l2.000000,3.500000C33.599998,34.299999 36.000000,30.400000 36.000000,26.000000zM24.000000,6.000000C13.000000,6.000000 4.000000,15.000000 4.000000,26.000000c0.000000,7.400000 4.000000,13.800000 10.000000,17.299999l2.000000,-3.500000c-4.800000,-2.800000 -8.000000,-7.900000 -8.000000,-13.800000c0.000000,-8.800000 7.200000,-16.000000 16.000000,-16.000000s16.000000,7.200000 16.000000,16.000000c0.000000,5.900000 -3.200000,11.100000 -8.000000,13.800000l2.000000,3.500000c6.000000,-3.500000 10.000000,-9.900000 10.000000,-17.299999C44.000000,15.000000 35.000000,6.000000 24.000000,6.000000z"/> </vector> diff --git a/core/res/res/drawable/ic_cab_done_material.xml b/core/res/res/drawable/time_picker_header_material.xml index a370288..cdb92b6 100644 --- a/core/res/res/drawable/ic_cab_done_material.xml +++ b/core/res/res/drawable/time_picker_header_material.xml @@ -14,6 +14,9 @@ limitations under the License. --> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_cab_done_mtrl_alpha" - android:tint="?attr/colorControlNormal" /> +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?attr/colorControlHighlight"> + <item> + <color android:color="?attr/colorAccent" /> + </item> +</ripple> diff --git a/core/res/res/layout-land/time_picker_holo.xml b/core/res/res/layout-land/time_picker_holo.xml index f316f1b..ce90a5b 100644 --- a/core/res/res/layout-land/time_picker_holo.xml +++ b/core/res/res/layout-land/time_picker_holo.xml @@ -21,7 +21,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" - android:focusable="true" android:layout_marginLeft="@dimen/timepicker_minimum_margin_sides" android:layout_marginRight="@dimen/timepicker_minimum_margin_sides" android:layout_marginTop="@dimen/timepicker_minimum_margin_top_bottom" @@ -42,7 +41,5 @@ android:id="@+id/radial_picker" android:layout_width="@dimen/timepicker_radial_picker_dimen" android:layout_height="match_parent" - android:layout_gravity="center" - android:focusable="true" - android:focusableInTouchMode="true" /> + android:layout_gravity="center" /> </LinearLayout> diff --git a/core/res/res/layout/action_mode_close_item_material.xml b/core/res/res/layout/action_mode_close_item_material.xml new file mode 100644 index 0000000..8eb780b --- /dev/null +++ b/core/res/res/layout/action_mode_close_item_material.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ImageButton xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/action_mode_close_button" + android:focusable="true" + android:clickable="true" + android:paddingStart="8dip" + android:src="?android:attr/actionModeCloseDrawable" + style="?android:attr/actionModeCloseButtonStyle" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginEnd="16dip" /> diff --git a/core/res/res/layout/preference_material.xml b/core/res/res/layout/preference_material.xml index 778e70a..a137149 100644 --- a/core/res/res/layout/preference_material.xml +++ b/core/res/res/layout/preference_material.xml @@ -24,7 +24,8 @@ android:gravity="center_vertical" android:paddingStart="?attr/listPreferredItemPaddingStart" android:paddingEnd="?attr/listPreferredItemPaddingEnd" - android:background="?attr/activatedBackgroundIndicator"> + android:background="?attr/activatedBackgroundIndicator" + android:clipToPadding="false"> <LinearLayout android:id="@+id/icon_frame" diff --git a/core/res/res/layout/screen_toolbar.xml b/core/res/res/layout/screen_toolbar.xml index 039e89f..88c9cf6 100644 --- a/core/res/res/layout/screen_toolbar.xml +++ b/core/res/res/layout/screen_toolbar.xml @@ -41,6 +41,7 @@ This is an optimized layout for a screen with a toolbar enabled. android:id="@+id/action_bar" android:layout_width="match_parent" android:layout_height="wrap_content" + android:navigationContentDescription="@string/action_bar_up_description" style="?attr/toolbarStyle" /> <com.android.internal.widget.ActionBarContextView android:id="@+id/action_context_bar" diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml index 483eb6d..08d2211 100644 --- a/core/res/res/layout/time_picker_holo.xml +++ b/core/res/res/layout/time_picker_holo.xml @@ -18,20 +18,17 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:orientation="vertical" - android:focusable="true" > + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="vertical"> <include - layout="@layout/time_header_label" - android:layout_width="match_parent" - android:layout_height="@dimen/timepicker_header_height" - android:layout_gravity="center" /> + layout="@layout/time_header_label" + android:layout_width="match_parent" + android:layout_height="@dimen/timepicker_header_height" + android:layout_gravity="center" /> <android.widget.RadialTimePickerView - android:id="@+id/radial_picker" - android:layout_width="wrap_content" - android:layout_height="@dimen/timepicker_radial_picker_dimen" - android:layout_gravity="center" - android:focusable="true" - android:focusableInTouchMode="true" /> + android:id="@+id/radial_picker" + android:layout_width="wrap_content" + android:layout_height="@dimen/timepicker_radial_picker_dimen" + android:layout_gravity="center" /> </LinearLayout> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index b6c876d..35ff766 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1228,9 +1228,9 @@ <string name="smv_application" msgid="3307209192155442829">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil své vlastní vynucené zásady StrictMode."</string> <string name="android_upgrading_title" msgid="1584192285441405746">"Android se upgraduje..."</string> - <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimalizace aplikace <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> + <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimalizování aplikace <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Spouštění aplikací."</string> - <string name="android_upgrading_complete" msgid="1405954754112999229">"Probíhá dokončování spouštění."</string> + <string name="android_upgrading_complete" msgid="1405954754112999229">"Dokončování inicializace."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Běží aplikace <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Dotykem přepnete aplikaci"</string> <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Přepnout aplikace?"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 451ac5d..fb635dd 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1294,7 +1294,7 @@ <string name="sms_control_yes" msgid="3663725993855816807">"Autoriser"</string> <string name="sms_control_no" msgid="625438561395534982">"Refuser"</string> <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> souhaite envoyer un message à <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string> - <string name="sms_short_code_details" msgid="5873295990846059400">"Ce "<b>"peut entraîner des frais"</b>" sur votre compte."</string> + <string name="sms_short_code_details" msgid="5873295990846059400">"Ceci "<b>"peut entraîner des frais"</b>" sur votre compte."</string> <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Cela entraînera des frais sur votre compte."</b></string> <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Envoyer"</string> <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Annuler"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 88adba5..7add9a6 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1294,8 +1294,8 @@ <string name="sms_control_yes" msgid="3663725993855816807">"Izinkan"</string> <string name="sms_control_no" msgid="625438561395534982">"Tolak"</string> <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ingin mengirim pesan kepada <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string> - <string name="sms_short_code_details" msgid="5873295990846059400">"Tindakan ini "<b>"dapat menimbulkan tagihan"</b>" terhadap akun seluler Anda."</string> - <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Tindakan ini akan menimbulkan tagihan terhadap akun seluler Anda."</b></string> + <string name="sms_short_code_details" msgid="5873295990846059400">"Tindakan ini "<b>"dapat menimbulkan tagihan"</b>" untuk ponsel Anda."</string> + <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Tindakan ini akan menimbulkan tagihan untuk ponsel Anda."</b></string> <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Kirim"</string> <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Batal"</string> <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Ingat pilihan saya"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 3120104..7a72fd3 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1588,7 +1588,7 @@ <string name="media_route_status_in_use" msgid="4533786031090198063">"בשימוש"</string> <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"מסך מובנה"</string> <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"מסך HDMI"</string> - <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"שכבת על #<xliff:g id="ID">%1$d</xliff:g>"</string> + <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"שכבת-על #<xliff:g id="ID">%1$d</xliff:g>"</string> <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", מאובטח"</string> <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"העברת מסך מתבצעת"</string> diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml index 423e250..2778b6e 100644 --- a/core/res/res/values-mcc310-mnc004/config.xml +++ b/core/res/res/values-mcc310-mnc004/config.xml @@ -34,4 +34,11 @@ </string-array> <bool name="config_auto_attach_data_on_creation">false</bool> + + <!-- Values for GPS configuration (Verizon) --> + <string-array translatable="false" name="config_gpsParameters"> + <item>CAPABILITIES=0x31</item> + <item>LPP_PROFILE=3</item> + <item>GPS_LOCK=3</item> + </string-array> </resources> diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml index 62001d9..3b95db5 100644 --- a/core/res/res/values-mcc310-mnc120/config.xml +++ b/core/res/res/values-mcc310-mnc120/config.xml @@ -25,4 +25,10 @@ --> <integer name="config_mobile_mtu">1422</integer> + <!-- Values for GPS configuration (Sprint) --> + <string-array translatable="false" name="config_gpsParameters"> + <item>CAPABILITIES=0x31</item> + <item>GPS_LOCK=3</item> + <item>LPP_PROFILE=2</item> + </string-array> </resources> diff --git a/core/res/res/values-mcc310-mnc150/config.xml b/core/res/res/values-mcc310-mnc150/config.xml index f1936f4..00d2db8 100644 --- a/core/res/res/values-mcc310-mnc150/config.xml +++ b/core/res/res/values-mcc310-mnc150/config.xml @@ -33,4 +33,10 @@ <item>315</item> <item>316</item> </string-array> + <!-- Values for GPS configuration (AT&T) --> + <string-array translatable="false" name="config_gpsParameters"> + <item>CAPABILITIES=0x33</item> + <item>LPP_PROFILE=3</item> + <item>GPS_LOCK=1</item> + </string-array> </resources> diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml index 00cdaeb..2f9394a 100644 --- a/core/res/res/values-mcc310-mnc260/config.xml +++ b/core/res/res/values-mcc310-mnc260/config.xml @@ -25,9 +25,10 @@ --> <integer name="config_mobile_mtu">1440</integer> - <!-- Values for GPS configuration --> + <!-- Values for GPS configuration (T-Mobile) --> <string-array translatable="false" name="config_gpsParameters"> - <item>"SUPL_PORT=7279"</item> + <item>CAPABILITEIS=0x33</item> <item>GPS_LOCK=1</item> + <item>LPP_PROFILE=2</item> </string-array> </resources> diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml index 9e63047..edf6d9f 100644 --- a/core/res/res/values-mcc310-mnc410/config.xml +++ b/core/res/res/values-mcc310-mnc410/config.xml @@ -40,8 +40,15 @@ <item>315</item> <item>316</item> </string-array> - <!-- Values for GPS configuration --> + <!-- Values for GPS configuration (AT&T) --> <string-array translatable="false" name="config_gpsParameters"> - <item>"SUPL_HOST=supl.google.com"</item> + <item>CAPABILITIES=0x33</item> + <item>GPS_LOCK=1</item> + <item>LPP_PROFILE=3</item> + </string-array> + <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD --> + <string-array name="config_twoDigitNumberPattern"> + <item>"0"</item> + <item>"00"</item> </string-array> </resources> diff --git a/core/res/res/values-mcc311-mnc190/config.xml b/core/res/res/values-mcc311-mnc190/config.xml index a6c4d1b..b4e436d 100644 --- a/core/res/res/values-mcc311-mnc190/config.xml +++ b/core/res/res/values-mcc311-mnc190/config.xml @@ -37,4 +37,11 @@ note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> <string translatable="false" name="config_tether_apndata">Tether,broadband.cellular1.net,,,,,,,,,311,190,,DUN</string> + <!-- Values for GPS configuration (Sprint) --> + <string-array translatable="false" name="config_gpsParameters"> + <item>CAPABILITIES=0x31</item> + <item>GPS_LOCK=3</item> + <item>LPP_PROFILE=2</item> + </string-array> + </resources> diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml index e5af60b..cd5d55b 100644 --- a/core/res/res/values-mcc311-mnc480/config.xml +++ b/core/res/res/values-mcc311-mnc480/config.xml @@ -44,4 +44,11 @@ <bool name="config_mobile_allow_volte_vt">false</bool> <bool name="config_auto_attach_data_on_creation">false</bool> + + <!-- Values for GPS configuration (Verizon) --> + <string-array translatable="false" name="config_gpsParameters"> + <item>CAPABILITIES=0x31</item> + <item>GPS_LOCK=3</item> + <item>LPP_PROFILE=3</item> + </string-array> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 0a109ba..2e0792a 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1774,6 +1774,6 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir padrão de desbloqueio antes de liberar"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir senha antes de liberar"</string> - <string name="battery_saver_description" msgid="2510530476513605742">"Para ajudar a melhorar a vida útil da bateria, a economia de bateria reduz o desempenho do dispositivo e restringe a vibração e a maioria dos dados em segundo plano. É possível que apps de e-mail, mensagens, entre outros, que dependem de sincronização não sejam atualizados a menos que sejam abertos.\n\nA economia de bateria é desativada automaticamente quando o dispositivo estiver carregando."</string> + <string name="battery_saver_description" msgid="2510530476513605742">"Para ajudar a melhorar a vida útil da bateria, a economia de bateria reduz o desempenho do dispositivo e restringe a vibração e a maioria dos dados em segundo plano. É possível que apps de e-mail, mensagens, entre outros que dependem de sincronização não sejam atualizados a menos que sejam abertos.\n\nA economia de bateria é desativada automaticamente quando o dispositivo estiver carregando."</string> <string name="downtime_condition_summary" msgid="8761776337475705749">"Até o período de inatividade terminar às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index daad675..f95d29d 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1295,7 +1295,7 @@ <string name="sms_control_no" msgid="625438561395534982">"Kataza"</string> <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ingependa kutuma ujumbe kwa <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string> <string name="sms_short_code_details" msgid="5873295990846059400">"Hii "<b>"huenda ikasababisha ulipe gharama"</b>" kwenye akaunti ya kifaa chako cha mkononi."</string> - <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Hii itasababisha ulipe gharama kwenye akaunti ya kifaa chako cha mkononi."</b></string> + <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Hii itafanya ulipe gharama kwenye akaunti ya kifaa chako cha mkononi."</b></string> <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Tuma"</string> <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Ghairi"</string> <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Kumbuka chaguo yangu"</string> diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml index 516bea4..2c0ed15 100644 --- a/core/res/res/values-ta-rIN/strings.xml +++ b/core/res/res/values-ta-rIN/strings.xml @@ -54,17 +54,17 @@ <string name="serviceErased" msgid="1288584695297200972">"அழித்தல் வெற்றியடைந்தது."</string> <string name="passwordIncorrect" msgid="7612208839450128715">"தவறான கடவுச்சொல்."</string> <string name="mmiComplete" msgid="8232527495411698359">"MMI நிறைவடைந்தது."</string> - <string name="badPin" msgid="9015277645546710014">"உள்ளிட்ட பழைய PIN தவறானது."</string> + <string name="badPin" msgid="9015277645546710014">"உள்ளிட்ட பழைய பின் தவறானது."</string> <string name="badPuk" msgid="5487257647081132201">"உள்ளிட்ட PUK2 தவறானது."</string> <string name="mismatchPin" msgid="609379054496863419">"உள்ளிட்ட PINகள் பொருந்தவில்லை."</string> - <string name="invalidPin" msgid="3850018445187475377">"4 இலிருந்து 8 எண்கள் வரையுள்ள PIN ஐத் தட்டச்சு செய்யவும்."</string> + <string name="invalidPin" msgid="3850018445187475377">"4 இலிருந்து 8 எண்கள் வரையுள்ள பின் ஐத் தட்டச்சு செய்யவும்."</string> <string name="invalidPuk" msgid="8761456210898036513">"8 அல்லது அதற்கு மேல் எண்கள் உள்ள PUK ஐத் தட்டச்சு செய்யவும்."</string> - <string name="needPuk" msgid="919668385956251611">"உங்கள் SIM கார்டு PUK பூட்டுதல் செய்யப்பட்டுள்ளது. அதைத் திறக்க PUK குறியீட்டைத் உள்ளிடவும்."</string> - <string name="needPuk2" msgid="4526033371987193070">"SIM கார்டைத் தடுப்பு நீக்க PUK2 ஐ உள்ளிடவும்."</string> - <string name="enablePin" msgid="209412020907207950">"தோல்வி, SIM/RUIM பூட்டை இயக்கவும்."</string> + <string name="needPuk" msgid="919668385956251611">"உங்கள் சிம் கார்டு PUK பூட்டுதல் செய்யப்பட்டுள்ளது. அதைத் திறக்க PUK குறியீட்டைத் உள்ளிடவும்."</string> + <string name="needPuk2" msgid="4526033371987193070">"சிம் கார்டைத் தடுப்பு நீக்க PUK2 ஐ உள்ளிடவும்."</string> + <string name="enablePin" msgid="209412020907207950">"தோல்வி, சிம்/RUIM பூட்டை இயக்கவும்."</string> <plurals name="pinpuk_attempts"> - <item quantity="one" msgid="6596245285809790142">"SIM பூட்டப்படுவதற்கு முன், நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</item> - <item quantity="other" msgid="7530597808358774740">"SIM பூட்டப்படுவதற்கு முன், நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</item> + <item quantity="one" msgid="6596245285809790142">"சிம் பூட்டப்படுவதற்கு முன், நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</item> + <item quantity="other" msgid="7530597808358774740">"சிம் பூட்டப்படுவதற்கு முன், நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</item> </plurals> <string name="imei" msgid="2625429890869005782">"IMEI"</string> <string name="meid" msgid="4841221237681254195">"MEID"</string> @@ -76,7 +76,7 @@ <string name="CwMmi" msgid="9129678056795016867">"அழைப்பு காத்திருப்பு"</string> <string name="BaMmi" msgid="455193067926770581">"அழைப்புத் தவிர்ப்பு"</string> <string name="PwdMmi" msgid="7043715687905254199">"கடவுச்சொல்லை மாற்று"</string> - <string name="PinMmi" msgid="3113117780361190304">"PIN ஐ மாற்று"</string> + <string name="PinMmi" msgid="3113117780361190304">"பின்னை மாற்று"</string> <string name="CnipMmi" msgid="3110534680557857162">"இருக்கும் எண்ணை அழைக்கிறது"</string> <string name="CnirMmi" msgid="3062102121430548731">"அழைப்பு எண் வரையறுக்கப்பட்டது"</string> <string name="ThreeWCMmi" msgid="9051047170321190368">"மும்முனை அழைப்பு"</string> @@ -289,11 +289,11 @@ <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"நிகழ்வுகளுக்குச் செய்தி வழியாகப் பதிலை அனுப்புதல்"</string> <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"உள்வரும் அழைப்புகளுக்கான நிகழ்வுகளுக்கு, செய்தி வழியாகப் பதிலளிப்பதை நிர்வகிப்பதற்கு, பிற மெசேஜ் பயன்பாடுகளுக்குக் கோரிக்கைகளை அனுப்புவதற்குப் பயன்பாட்டை அனுமதிக்கிறது."</string> <string name="permlab_readSms" msgid="8745086572213270480">"உங்கள் உரைச் செய்திகளை (SMS அல்லது MMS) படித்தல்"</string> - <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"உங்கள் டேப்லெட் அல்லது SIM கார்டில் சேமிக்கப்பட்ட SMS குறுஞ்செய்திகளைப் படிக்க பயன்பாட்டை அனுமதிக்கிறது. SMS குறுஞ்செய்திகளின் உள்ளடக்கம் அல்லது ரகசியத்தன்மை ஆகியவற்றைப் பொருட்படுத்தாமல் அச்செய்திகளைப் படிக்க பயன்பாட்டை இது அனுமதிக்கிறது."</string> - <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"உங்கள் மொபைல் அல்லது SIM கார்டில் சேமிக்கப்பட்ட SMS குறுஞ்செய்திகளைப் படிக்கப் பயன்பாட்டை அனுமதிக்கிறது. SMS குறுஞ்செய்திகளின் உள்ளடக்கம் அல்லது ரகசியத்தன்மை ஆகியவற்றைப் பொருட்படுத்தாமல் அச்செய்திகளைப் படிக்க பயன்பாட்டை இது அனுமதிக்கிறது."</string> + <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"உங்கள் டேப்லெட் அல்லது சிம் கார்டில் சேமிக்கப்பட்ட SMS குறுஞ்செய்திகளைப் படிக்க பயன்பாட்டை அனுமதிக்கிறது. SMS குறுஞ்செய்திகளின் உள்ளடக்கம் அல்லது ரகசியத்தன்மை ஆகியவற்றைப் பொருட்படுத்தாமல் அச்செய்திகளைப் படிக்க பயன்பாட்டை இது அனுமதிக்கிறது."</string> + <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"உங்கள் மொபைல் அல்லது சிம் கார்டில் சேமிக்கப்பட்ட SMS குறுஞ்செய்திகளைப் படிக்கப் பயன்பாட்டை அனுமதிக்கிறது. SMS குறுஞ்செய்திகளின் உள்ளடக்கம் அல்லது ரகசியத்தன்மை ஆகியவற்றைப் பொருட்படுத்தாமல் அச்செய்திகளைப் படிக்க பயன்பாட்டை இது அனுமதிக்கிறது."</string> <string name="permlab_writeSms" msgid="3216950472636214774">"உங்கள் உரைச் செய்திகளைத் (SMS அல்லது MMS) திருத்துதல்"</string> - <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"டேப்லெட் அல்லது SIM கார்டில் சேமிக்கப்பட்ட SMS செய்திகளை எழுத, பயன்பாட்டை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் பயன்பாடுகள் செய்திகளை நீக்கலாம்."</string> - <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"ஃபோன் அல்லது SIM கார்டில் சேமிக்கப்பட்ட SMS செய்திகளை எழுத, பயன்பாட்டை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் பயன்பாடுகள் செய்திகளை நீக்கலாம்."</string> + <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"டேப்லெட் அல்லது சிம் கார்டில் சேமிக்கப்பட்ட SMS செய்திகளை எழுத, பயன்பாட்டை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் பயன்பாடுகள் செய்திகளை நீக்கலாம்."</string> + <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"ஃபோன் அல்லது சிம் கார்டில் சேமிக்கப்பட்ட SMS செய்திகளை எழுத, பயன்பாட்டை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் பயன்பாடுகள் செய்திகளை நீக்கலாம்."</string> <string name="permlab_receiveWapPush" msgid="5991398711936590410">"உரைச் செய்திகளைப் (WAP) பெறுதல்"</string> <string name="permdesc_receiveWapPush" msgid="748232190220583385">"WAP செய்திகளைப் பெற, செயற்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது. உங்களுக்கு அனுப்பப்படும் செய்திகளை உங்களுக்குக் காட்டாமல் கண்காணிக்க அல்லது நீக்குவதற்கான திறன் இந்த அனுமதியில் உள்ளடங்கும்."</string> <string name="permlab_receiveBluetoothMap" msgid="7593811487142360528">"Bluetooth செய்திகளைப் (MAP) பெறுதல்"</string> @@ -541,8 +541,8 @@ <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ஒலியளவு மற்றும் வெளியீட்டிற்கு ஸ்பீக்கர்கள் பயன்படுத்தப்படுவது போன்ற ஒட்டுமொத்த ஆடியோ அமைப்புகளைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string> <string name="permlab_recordAudio" msgid="3876049771427466323">"ஆடியோவைப் பதிவுசெய்தல்"</string> <string name="permdesc_recordAudio" msgid="4906839301087980680">"மைக்ரோஃபோன் மூலம் ஆடியோவைப் பதிவுசெய்ய பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இல்லாமல் எந்நேரத்திலும் ஆடியோவைப் பதிவுசெய்ய இந்த அனுமதி பயன்பாட்டை அனுமதிக்கிறது."</string> - <string name="permlab_sim_communication" msgid="1180265879464893029">"SIM தகவல்தொடர்பு"</string> - <string name="permdesc_sim_communication" msgid="5725159654279639498">"SIM க்குக் கட்டளைகளை அனுப்ப பயன்பாட்டை அனுமதிக்கிறது. இது மிகவும் ஆபத்தானதாகும்."</string> + <string name="permlab_sim_communication" msgid="1180265879464893029">"சிம் தகவல்தொடர்பு"</string> + <string name="permdesc_sim_communication" msgid="5725159654279639498">"சிம் க்குக் கட்டளைகளை அனுப்ப பயன்பாட்டை அனுமதிக்கிறது. இது மிகவும் ஆபத்தானதாகும்."</string> <string name="permlab_camera" msgid="3616391919559751192">"படங்கள் மற்றும் வீடியோக்களை எடுத்தல்"</string> <string name="permdesc_camera" msgid="8497216524735535009">"கேமரா மூலமாகப் படங்களையும், வீடியோக்களையும் எடுக்க பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இன்றி கேமராவை எந்நேரத்திலும் பயன்படுத்தப் பயன்பாட்டை இது அனுமதிக்கிறது."</string> <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"கேமரா பயன்பாட்டில் இருக்கும்போது டிரான்ஸ்மிட் இன்டிகேட்டர் LED ஐ முடக்குதல்"</string> @@ -882,14 +882,14 @@ <string name="sipAddressTypeWork" msgid="6920725730797099047">"அலுவலகம்"</string> <string name="sipAddressTypeOther" msgid="4408436162950119849">"மற்றவை"</string> <string name="quick_contacts_not_available" msgid="746098007828579688">"இதைப் பார்ப்பதற்குகந்த பயன்பாடு எதுவும் நிறுவப்படவில்லை."</string> - <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN குறியீட்டை உள்ளிடவும்"</string> - <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK மற்றும் புதிய PIN குறியீட்டை உள்ளிடவும்"</string> + <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"பின் குறியீட்டை உள்ளிடவும்"</string> + <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK மற்றும் புதிய பின் குறியீட்டை உள்ளிடவும்"</string> <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK குறியீடு"</string> - <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"புதிய PIN குறியீடு"</string> + <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"புதிய பின் குறியீடு"</string> <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"கடவுச்சொல்லை உள்ளிட, தொடவும்"</font></string> <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"திறக்க, கடவுச்சொல்லை உள்ளிடவும்"</string> - <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"திறக்க, PIN ஐ உள்ளிடவும்"</string> - <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"தவறான PIN குறியீடு."</string> + <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"திறக்க, பின்னை உள்ளிடவும்"</string> + <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"தவறான பின் குறியீடு."</string> <string name="keyguard_label_text" msgid="861796461028298424">"தடைநீக்க, மெனுவை அழுத்தி பின்பு 0 ஐ அழுத்தவும்."</string> <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"அவசர எண்"</string> <string name="lockscreen_carrier_default" msgid="8963839242565653192">"சேவை இல்லை."</string> @@ -907,13 +907,13 @@ <string name="lockscreen_charged" msgid="321635745684060624">"சார்ஜ் செய்யப்பட்டது"</string> <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> <string name="lockscreen_low_battery" msgid="1482873981919249740">"உங்கள் சார்ஜரை இணைக்கவும்."</string> - <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM கார்டு இல்லை"</string> - <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"டேப்லெட்டில் SIM கார்டு இல்லை."</string> - <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"தொலைபேசியில் SIM கார்டு இல்லை."</string> - <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"SIM கார்டைச் செருகவும்."</string> - <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM கார்டு இல்லை அல்லது படிக்கக்கூடியதாக இல்லை. SIM கார்டைச் செருகவும்."</string> - <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"பயன்படுத்த முடியாத SIM கார்டு."</string> - <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"உங்கள் SIM கார்டு நிரந்தரமாக முடக்கப்பட்டது.\n மற்றொரு SIM கார்டிற்காக உங்கள் வயர்லெஸ் சேவை வழங்குநரைத் தொடர்புகொள்ளவும்."</string> + <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"சிம் கார்டு இல்லை"</string> + <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"டேப்லெட்டில் சிம் கார்டு இல்லை."</string> + <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"தொலைபேசியில் சிம் கார்டு இல்லை."</string> + <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"சிம் கார்டைச் செருகவும்."</string> + <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"சிம் கார்டு இல்லை அல்லது படிக்கக்கூடியதாக இல்லை. சிம் கார்டைச் செருகவும்."</string> + <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"பயன்படுத்த முடியாத சிம் கார்டு."</string> + <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"உங்கள் சிம் கார்டு நிரந்தரமாக முடக்கப்பட்டது.\n மற்றொரு சிம் கார்டிற்காக உங்கள் வயர்லெஸ் சேவை வழங்குநரைத் தொடர்புகொள்ளவும்."</string> <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"முந்தைய ட்ராக்"</string> <string name="lockscreen_transport_next_description" msgid="573285210424377338">"அடுத்த ட்ராக்"</string> <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"இடைநிறுத்து"</string> @@ -923,13 +923,13 @@ <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"வேகமாக முன்செல்"</string> <string name="emergency_calls_only" msgid="6733978304386365407">"அவசர அழைப்புகள் மட்டும்"</string> <string name="lockscreen_network_locked_message" msgid="143389224986028501">"நெட்வொர்க் பூட்டப்பட்டது"</string> - <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM கார்டு PUK பூட்டுதல் செய்யப்பட்டுள்ளது."</string> + <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"சிம் கார்டு PUK பூட்டுதல் செய்யப்பட்டுள்ளது."</string> <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"பயனர் கையேட்டைப் பார்க்கவும் அல்லது வாடிக்கையாளர் சேவையைத் தொடர்புகொள்ளவும்."</string> - <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM கார்டு பூட்டப்பட்டுள்ளது."</string> - <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM கார்டைத் திறக்கிறது..."</string> + <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"சிம் கார்டு பூட்டப்பட்டுள்ளது."</string> + <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"சிம் கார்டைத் திறக்கிறது..."</string> <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"உங்கள் கடவுச்சொல்லை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> - <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"உங்கள் PIN ஐ <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> + <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"உங்கள் பின்னை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக வரைந்தால், உங்கள் Google உள்நுழைவைப் பயன்படுத்தி டேப்லெட்டைத் திறக்குமாறு கேட்கப்படுவீர்கள். \n\n <xliff:g id="NUMBER_2">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக வரைந்தால், உங்கள் Google உள்நுழைவைப் பயன்படுத்தி மொபைலைத் திறக்குமாறு கேட்கப்படுவீர்கள். \n\n <xliff:g id="NUMBER_2">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"டேப்லெட்டைத் தடைநீக்க <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, டேப்லெட்டானது ஆரம்ப இயல்புநிலைக்கு மீட்டமைக்கப்பட்டு, எல்லா பயனர் தரவும் இழக்கப்படும்."</string> @@ -1284,8 +1284,8 @@ <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"இணைவதற்கான அழைப்பு"</string> <string name="wifi_p2p_from_message" msgid="570389174731951769">"அனுப்புநர்:"</string> <string name="wifi_p2p_to_message" msgid="248968974522044099">"பெறுநர்:"</string> - <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"பின்வரும் அவசியமான PIN ஐ உள்ளிடவும்:"</string> - <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> + <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"பின்வரும் அவசியமான பின்னை உள்ளிடவும்:"</string> + <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"பின்:"</string> <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் டேப்லெட் இணைக்கப்படும்போது, வைஃபையிலிருந்து தற்காலிகமாகத் துண்டிக்கப்படும்."</string> <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் மொபைல் இணைக்கப்படும்போது, வைஃபையிலிருந்து தற்காலிகமாகத் துண்டிக்கப்படும்."</string> <string name="select_character" msgid="3365550120617701745">"எழுத்துக்குறியைச் செருகு"</string> @@ -1302,10 +1302,10 @@ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"அமைப்பு > பயன்பாடுகள் என்பதில் பிறகு நீங்கள் மாற்றலாம்"</string> <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"எப்போதும் அனுமதி"</string> <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"ஒருபோதும் அனுமதிக்காதே"</string> - <string name="sim_removed_title" msgid="6227712319223226185">"SIM கார்டு அகற்றப்பட்டது"</string> - <string name="sim_removed_message" msgid="5450336489923274918">"சரியான SIM கார்டைச் செருகி, மறுதொடக்கம் செய்யும் வரை செல்லுலார் நெட்வொர்க் கிடைக்காது."</string> + <string name="sim_removed_title" msgid="6227712319223226185">"சிம் கார்டு அகற்றப்பட்டது"</string> + <string name="sim_removed_message" msgid="5450336489923274918">"சரியான சிம் கார்டைச் செருகி, மறுதொடக்கம் செய்யும் வரை செல்லுலார் நெட்வொர்க் கிடைக்காது."</string> <string name="sim_done_button" msgid="827949989369963775">"முடிந்தது"</string> - <string name="sim_added_title" msgid="3719670512889674693">"SIM கார்டு சேர்க்கப்பட்டது"</string> + <string name="sim_added_title" msgid="3719670512889674693">"சிம் கார்டு சேர்க்கப்பட்டது"</string> <string name="sim_added_message" msgid="7797975656153714319">"செல்லுலார் நெட்வொர்க்கை அணுக உங்கள் சாதனத்தை மறுதொடக்கம் செய்யவும்."</string> <string name="sim_restart_button" msgid="4722407842815232347">"மறுதொடக்கம்"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"நேரத்தை அமை"</string> @@ -1568,7 +1568,7 @@ <string name="activity_resolver_use_once" msgid="2404644797149173758">"இப்போது மட்டும்"</string> <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s பணி சுயவிவரத்தை ஆதரிக்காது"</string> <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"டேப்லெட்"</string> - <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"மொபைல்"</string> + <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ஃபோன்"</string> <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ஹெட்ஃபோன்கள்"</string> <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"மொபைல் வைக்கும் கருவியின் ஸ்பீக்கர்கள்"</string> <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string> @@ -1600,21 +1600,21 @@ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"வடிவத்தை மறந்துவிட்டீர்களா"</string> <string name="kg_wrong_pattern" msgid="1850806070801358830">"தவறான வடிவம்"</string> <string name="kg_wrong_password" msgid="2333281762128113157">"தவறான கடவுச்சொல்"</string> - <string name="kg_wrong_pin" msgid="1131306510833563801">"தவறான PIN"</string> + <string name="kg_wrong_pin" msgid="1131306510833563801">"தவறான பின்"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> <string name="kg_pattern_instructions" msgid="398978611683075868">"உங்கள் வடிவத்தை வரையவும்"</string> - <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN ஐ உள்ளிடவும்"</string> - <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN ஐ உள்ளிடுக"</string> + <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"சிம் பின்னை உள்ளிடவும்"</string> + <string name="kg_pin_instructions" msgid="2377242233495111557">"பின்னை உள்ளிடுக"</string> <string name="kg_password_instructions" msgid="5753646556186936819">"கடவுச்சொல்லை உள்ளிடவும்"</string> - <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM தற்போது முடக்கப்பட்டுள்ளது. தொடர்வதற்கு PUK குறியீட்டை உள்ளிடவும். விவரங்களுக்கு மொபைல் நிறுவனங்களைத் தொடர்புகொள்ளவும்."</string> - <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"விரும்பிய PIN குறியீட்டை உள்ளிடவும்"</string> - <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"விரும்பிய PIN குறியீட்டை உறுதிப்படுத்தவும்"</string> - <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM கார்டின் தடையைநீக்குகிறது..."</string> - <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"தவறான PIN குறியீடு."</string> - <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4 இலிருந்து 8 எண்கள் வரையுள்ள PIN ஐ உள்ளிடவும்."</string> + <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"சிம் தற்போது முடக்கப்பட்டுள்ளது. தொடர்வதற்கு PUK குறியீட்டை உள்ளிடவும். விவரங்களுக்கு மொபைல் நிறுவனங்களைத் தொடர்புகொள்ளவும்."</string> + <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"விரும்பிய பின் குறியீட்டை உள்ளிடவும்"</string> + <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"விரும்பிய பின் குறியீட்டை உறுதிப்படுத்தவும்"</string> + <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"சிம் கார்டின் தடையைநீக்குகிறது..."</string> + <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"தவறான பின் குறியீடு."</string> + <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4 இலிருந்து 8 எண்கள் வரையுள்ள பின்னை உள்ளிடவும்."</string> <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK குறியீட்டில் 8 எழுத்துக்குறிகள் இருக்க வேண்டும்."</string> - <string name="kg_invalid_puk" msgid="3638289409676051243">"சரியான PUK குறியீட்டை மீண்டும் உள்ளிடவும். தொடர் முயற்சிகள் SIM ஐ நிரந்தரமாக முடக்கிவிடும்."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN குறியீடுகள் பொருந்தவில்லை"</string> + <string name="kg_invalid_puk" msgid="3638289409676051243">"சரியான PUK குறியீட்டை மீண்டும் உள்ளிடவும். தொடர் முயற்சிகள் சிம் ஐ நிரந்தரமாக முடக்கிவிடும்."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"பின் குறியீடுகள் பொருந்தவில்லை"</string> <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"அதிகமான வடிவ முயற்சிகள்"</string> <string name="kg_login_instructions" msgid="1100551261265506448">"திறக்க, உங்கள் Google கணக்கு மூலம் உள்நுழையவும்."</string> <string name="kg_login_username_hint" msgid="5718534272070920364">"பயனர்பெயர் (மின்னஞ்சல்)"</string> @@ -1623,7 +1623,7 @@ <string name="kg_login_invalid_input" msgid="5754664119319872197">"தவறான பயனர்பெயர் அல்லது கடவுச்சொல்."</string> <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"உங்கள் பயனர்பெயர் அல்லது கடவுச்சொல்லை மறந்துவிட்டீர்களா?\n"<b>"google.com/accounts/recovery"</b>" ஐப் பார்வையிடவும்."</string> <string name="kg_login_checking_password" msgid="1052685197710252395">"கணக்கைச் சரிபார்க்கிறது…"</string> - <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"உங்கள் PIN ஐ <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> + <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"உங்கள் பின்னை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"உங்கள் கடவுச்சொல்லை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகளில் மீண்டும் முயற்சிக்கவும்."</string> <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"டேப்லெட்டைத் திறக்க <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, டேப்லெட்டானது ஆரம்பநிலைக்கு மீட்டமைக்கப்பட்டு, எல்லா பயனர் தரவையும் இழப்பீர்கள்."</string> @@ -1734,15 +1734,15 @@ <string name="reason_service_unavailable" msgid="7824008732243903268">"பிரிண்டர் இயக்கத்தில் இல்லை"</string> <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> சேவை நிறுவப்பட்டது"</string> <string name="print_service_installed_message" msgid="5897362931070459152">"இயக்குவதற்குத் தட்டவும்"</string> - <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"நிர்வாகி PIN ஐ உள்ளிடவும்"</string> - <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN ஐ உள்ளிடவும்"</string> + <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"நிர்வாகி பின்னை உள்ளிடவும்"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"பின்னை உள்ளிடவும்"</string> <string name="restr_pin_incorrect" msgid="8571512003955077924">"தவறானது"</string> - <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"நடப்பு PIN"</string> - <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"புதிய PIN"</string> - <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"புதிய PIN ஐ உறுதிப்படுத்தவும்"</string> - <string name="restr_pin_create_pin" msgid="8017600000263450337">"வரம்புகளைத் திருத்துவதற்கு PIN ஐ உருவாக்கவும்"</string> + <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"நடப்பு பின்"</string> + <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"புதிய பின்"</string> + <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"புதிய பின்னை உறுதிப்படுத்தவும்"</string> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"வரம்புகளைத் திருத்துவதற்கு பின்னை உருவாக்கவும்"</string> <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINகள் பொருந்தவில்லை. மீண்டும் முயற்சிக்கவும்."</string> - <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN மிகவும் சிறியதாக உள்ளது. குறைந்தது 4 இலக்கங்கள் இருக்க வேண்டும்."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"பின் மிகவும் சிறியதாக உள்ளது. குறைந்தது 4 இலக்கங்கள் இருக்க வேண்டும்."</string> <plurals name="restr_pin_countdown"> <item quantity="one" msgid="311050995198548675">"1 வினாடி கழித்து முயற்சிக்கவும்"</item> <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்"</item> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index c4a6e53c..cd0ef0b 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1294,8 +1294,8 @@ <string name="sms_control_yes" msgid="3663725993855816807">"允許"</string> <string name="sms_control_no" msgid="625438561395534982">"拒絕"</string> <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> 要求將訊息傳送至 <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>。"</string> - <string name="sms_short_code_details" msgid="5873295990846059400">"這"<b>"可能會將收費計入"</b>"您的流動服務帳戶中。"</string> - <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"這會將收費計入您的流動服務帳戶中。"</b></string> + <string name="sms_short_code_details" msgid="5873295990846059400">"您的流動服務帳戶"<b>"可能因此繳付費用"</b>"。"</string> + <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"您的流動服務帳戶將因此繳付費用。"</b></string> <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"發送"</string> <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"取消"</string> <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"記住我的選擇"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 093ce63..fdb54ec 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -376,7 +376,7 @@ <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"允許應用程式啟動完整備份確認使用者介面 (不建議任何應用程式使用)。"</string> <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"顯示未授權視窗"</string> <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"允許應用程式為內部系統使用者介面建立視窗 (不建議一般應用程式使用)。"</string> - <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"在其他應用程式之上顯示内容"</string> + <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"在其他應用程式之上顯示內容"</string> <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"允許應用程式在其他應用程式頂層或使用者介面的特定部分繪圖。這可能會干擾您在所有應用程式中的介面使用行為,或是使您在其他應用程式中預期看到的內容發生變化。"</string> <string name="permlab_setAnimationScale" msgid="2805103241153907174">"編輯全域動畫速度"</string> <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"允許應用程式隨時變更全域的動畫速度 (更快或更慢)。"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index a798d2e..3629cbb 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -514,8 +514,8 @@ <!-- Flag indicating whether this Window's transition should overlap with the exiting transition of the called Activity when the called Activity finishes. Corresponds to - {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. --> - <attr name="windowAllowExitTransitionOverlap" format="boolean"/> + {@link android.view.Window#setAllowReturnTransitionOverlap(boolean)}. --> + <attr name="windowAllowReturnTransitionOverlap" format="boolean"/> <!-- Indicates whether or not shared elements should use an overlay during transitions. The default value is true. --> @@ -1726,6 +1726,34 @@ <enum name="KEYCODE_LAST_CHANNEL" value="229" /> <enum name="KEYCODE_TV_DATA_SERVICE" value="230" /> <enum name="KEYCODE_VOICE_ASSIST" value="231" /> + <enum name="KEYCODE_TV_RADIO_SERVICE" value="232" /> + <enum name="KEYCODE_TV_TELETEXT" value="233" /> + <enum name="KEYCODE_TV_NUMBER_ENTRY" value="234" /> + <enum name="KEYCODE_TV_TERRESTRIAL_ANALOG" value="235" /> + <enum name="KEYCODE_TV_TERRESTRIAL_DIGITAL" value="236" /> + <enum name="KEYCODE_TV_SATELLITE" value="237" /> + <enum name="KEYCODE_TV_SATELLITE_BS" value="238" /> + <enum name="KEYCODE_TV_SATELLITE_CS" value="239" /> + <enum name="KEYCODE_TV_SATELLITE_SERVICE" value="240" /> + <enum name="KEYCODE_TV_NETWORK" value="241" /> + <enum name="KEYCODE_TV_ANTENNA_CABLE" value="242" /> + <enum name="KEYCODE_TV_INPUT_HDMI_1" value="243" /> + <enum name="KEYCODE_TV_INPUT_HDMI_2" value="244" /> + <enum name="KEYCODE_TV_INPUT_HDMI_3" value="245" /> + <enum name="KEYCODE_TV_INPUT_HDMI_4" value="246" /> + <enum name="KEYCODE_TV_INPUT_COMPOSITE_1" value="247" /> + <enum name="KEYCODE_TV_INPUT_COMPOSITE_2" value="248" /> + <enum name="KEYCODE_TV_INPUT_COMPONENT_1" value="249" /> + <enum name="KEYCODE_TV_INPUT_COMPONENT_2" value="250" /> + <enum name="KEYCODE_TV_INPUT_VGA_1" value="251" /> + <enum name="KEYCODE_TV_AUDIO_DESCRIPTION" value="252" /> + <enum name="KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP" value="253" /> + <enum name="KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN" value="254" /> + <enum name="KEYCODE_TV_ZOOM_MODE" value="255" /> + <enum name="KEYCODE_TV_CONTENTS_MENU" value="256" /> + <enum name="KEYCODE_TV_MEDIA_CONTEXT_MENU" value="257" /> + <enum name="KEYCODE_TV_TIMER_PROGRAMMING" value="258" /> + <enum name="KEYCODE_HELP" value="259" /> </attr> <!-- ***************************************************************** --> @@ -1853,8 +1881,8 @@ <!-- Flag indicating whether this Window's transition should overlap with the exiting transition of the called Activity when the called Activity finishes. Corresponds to - {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. --> - <attr name="windowAllowExitTransitionOverlap"/> + {@link android.view.Window#setAllowReturnTransitionOverlap(boolean)}. --> + <attr name="windowAllowReturnTransitionOverlap"/> <!-- Indicates whether or not shared elements should use an overlay during transitions. The default value is true. --> @@ -1921,6 +1949,8 @@ <attr name="listItemLayout" format="reference" /> <attr name="progressLayout" format="reference" /> <attr name="horizontalProgressLayout" format="reference" /> + <!-- @hide Whether fullDark, etc. should use default values if null. --> + <attr name="needsDefaultBackgrounds" format="boolean" /> </declare-styleable> <!-- Fragment animation class attributes. --> @@ -4316,7 +4346,7 @@ <!-- @hide The layout of the legacy DatePicker. --> <attr name="legacyLayout" /> <!-- The background color for the date selector 's day of week. --> - <attr name="dayOfWeekBackgroundColor" format="color" /> + <attr name="dayOfWeekBackground" format="color|reference" /> <!-- The text color for the date selector's day of week. --> <attr name="dayOfWeekTextAppearance" format="reference" /> <!-- The month's text appearance in the date selector. --> @@ -4325,8 +4355,8 @@ <attr name="headerDayOfMonthTextAppearance" format="reference" /> <!-- The year's text appearance in the date selector. --> <attr name="headerYearTextAppearance" format="reference" /> - <!-- The background color for the date selector. --> - <attr name="headerBackgroundColor" /> + <!-- The background for the date selector. --> + <attr name="headerBackground" /> <!-- @hide The selected text color for the date selector. Used as a backup if the text appearance does not explicitly have a color set for the selected state. --> @@ -4623,29 +4653,29 @@ <attr name="legacyLayout" format="reference" /> <!-- @hide The layout of the time picker. --> <attr name="internalLayout" /> - <!-- The text appearance for the AM/PM header of the TimePicker. --> + <!-- The text appearance for the AM/PM header. --> <attr name="headerAmPmTextAppearance" format="reference" /> - <!-- The text appearance for the time header of the TimePicker. --> + <!-- The text appearance for the time header. --> <attr name="headerTimeTextAppearance" format="reference" /> <!-- @hide The text color for selected time header of the TimePicker. This will override the value from the text appearance if it does not explicitly have a color set for the selected state. --> <attr name="headerSelectedTextColor" format="color" /> - <!-- The background color for the header of the TimePicker. --> - <attr name="headerBackgroundColor" format="color" /> - <!-- The color for the hours/minutes numbers of the TimePicker. --> + <!-- The background for the header containing the currently selected time. --> + <attr name="headerBackground" /> + <!-- The color for the hours/minutes numbers. --> <attr name="numbersTextColor" format="color" /> - <!-- The background color for the hours/minutes numbers of the TimePicker. --> + <!-- The background color for the hours/minutes numbers. --> <attr name="numbersBackgroundColor" format="color" /> - <!-- The color for the AM/PM selectors of the TimePicker. --> + <!-- The color for the AM/PM selectors. --> <attr name="amPmTextColor" format="color" /> - <!-- The background color state list for the AM/PM selectors of the TimePicker. --> + <!-- The background color state list for the AM/PM selectors. --> <attr name="amPmBackgroundColor" format="color" /> <!-- @hide The background color for the AM/PM selectors of the TimePicker when selected. Used if the background color does not explicitly have a color set for the selected state. --> <attr name="amPmSelectedBackgroundColor" format="color" /> - <!-- The color for the hours/minutes selector of the TimePicker. --> + <!-- The color for the hours/minutes selector. --> <attr name="numbersSelectorColor" format="color" /> <!-- Defines the look of the widget. Prior to the L release, the only choice was spinner. As of L, with the Material theme selected, the default layout is clock, @@ -6570,12 +6600,12 @@ <flag name="vertical" value="0x2" /> </attr> <!-- Optional parameter which indicates where this widget can be shown, - ie. home screen, keyguard, recents or any combination thereof. + ie. home screen, keyguard, search bar or any combination thereof. Supports combined values using | operator. --> <attr name="widgetCategory" format="integer"> <flag name="home_screen" value="0x1" /> <flag name="keyguard" value="0x2" /> - <flag name="recents" value="0x4" /> + <flag name="searchbox" value="0x4" /> </attr> </declare-styleable> @@ -6627,6 +6657,53 @@ IDs (through the android:id attribute) instead of tags because they are faster and allow for compile-time type checking. --> <attr name="tag" /> + + <!-- The Transition that will be used to move Views out of the scene when the + fragment is removed, hidden, or detached when not popping the back stack. + Corresponds to {@link android.app.Fragment#setExitTransition( + android.transition.Transition)} --> + <attr name="fragmentExitTransition" format="reference"/> + + <!-- The Transition that will be used to move Views into the initial scene. + Corresponds to {@link android.app.Fragment#setEnterTransition( + android.transition.Transition)} --> + <attr name="fragmentEnterTransition" format="reference"/> + + <!-- The Transition that will be used for shared elements transferred into the content + Scene. + Corresponds to {@link android.app.Fragment#setSharedElementEnterTransition( + android.transition.Transition)} --> + <attr name="fragmentSharedElementEnterTransition" format="reference"/> + + <!-- The Transition that will be used to move Views out of the scene when the Fragment is + preparing to be removed, hidden, or detached because of popping the back stack. + Corresponds to {@link android.app.Fragment#setReturnTransition( + android.transition.Transition)} --> + <attr name="fragmentReturnTransition" format="reference"/> + + <!-- The Transition that will be used for shared elements transferred back during a + pop of the back stack. This Transition acts in the leaving Fragment. + Corresponds to {@link android.app.Fragment#setSharedElementReturnTransition( + android.transition.Transition)} --> + <attr name="fragmentSharedElementReturnTransition" format="reference"/> + + <!-- The Transition that will be used to move Views in to the scene when returning due + to popping a back stack. + Corresponds to {@link android.app.Fragment#setReenterTransition( + android.transition.Transition)} --> + <attr name="fragmentReenterTransition" format="reference"/> + + <!-- Sets whether the enter and exit transitions should overlap when transitioning + forward. + Corresponds to {@link android.app.Fragment#setAllowEnterTransitionOverlap( + boolean)} --> + <attr name="fragmentAllowEnterTransitionOverlap" format="reference"/> + + <!-- Sets whether the enter and exit transitions should overlap when transitioning + because of popping the back stack. + Corresponds to {@link android.app.Fragment#setAllowReturnTransitionOverlap( + boolean)} --> + <attr name="fragmentAllowReturnTransitionOverlap" format="reference"/> </declare-styleable> <!-- Use <code>device-admin</code> as the root tag of the XML resource that @@ -7040,6 +7117,8 @@ <attr name="backgroundSplit" /> <!-- Specifies a fixed height for the action mode bar. --> <attr name="height" /> + <!-- Specifies a layout to use for the "close" item at the starting edge. --> + <attr name="closeItemLayout" format="reference" /> </declare-styleable> <declare-styleable name="SearchView"> @@ -7072,6 +7151,7 @@ <attr name="queryBackground" format="reference" /> <!-- Background for the section containing the action (e.g. voice search) --> <attr name="submitBackground" format="reference" /> + <attr name="focusable" /> </declare-styleable> <declare-styleable name="Switch"> @@ -7112,9 +7192,9 @@ <!-- Drawable to use as the icon bitmap. --> <attr name="bitmap" format="reference" /> <!-- X coordinate of the icon hot spot. --> - <attr name="hotSpotX" format="float" /> + <attr name="hotSpotX" format="dimension" /> <!-- Y coordinate of the icon hot spot. --> - <attr name="hotSpotY" format="float" /> + <attr name="hotSpotY" format="dimension" /> </declare-styleable> <declare-styleable name="Storage"> @@ -7355,6 +7435,9 @@ <!-- @removed --> <attr name="__removed1" format="reference" /> + <!-- TODO: Spacer to be removed from here and public.xml --> + <attr name="__removed2" format="reference" /> + <!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the XML resource that describes TV content rating of a {@link android.media.tv.TvInputService}, which is referenced from its diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f5f079c..b63b91d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -374,7 +374,7 @@ <bool name="config_useAttentionLight">false</bool> <!-- If this is true, the screen will fade off. --> - <bool name="config_animateScreenLights">true</bool> + <bool name="config_animateScreenLights">false</bool> <!-- If this is true, key chords can be used to take a screenshot on the device. --> <bool name="config_enableScreenshotChord">true</bool> @@ -628,7 +628,7 @@ <integer name="config_notificationsBatteryLedOff">2875</integer> <!-- Number of notifications to keep in the notification service historical archive --> - <integer name="config_notificationServiceArchiveSize">250</integer> + <integer name="config_notificationServiceArchiveSize">100</integer> <!-- Allow the menu hard key to be disabled in LockScreen on some devices --> <bool name="config_disableMenuKeyInLockScreen">false</bool> @@ -1456,6 +1456,10 @@ <!-- Set to true if after a provisioning apn the radio should be restarted --> <bool name="config_restartRadioAfterProvisioning">false</bool> + <!-- Boolean indicating if RADIO POWER OFF is required on receiving SIM REFRESH with RESET. + This will be handled by modem if it is false. --> + <bool name="config_requireRadioPowerOffOnSimRefreshReset">false</bool> + <!-- Vibrator pattern to be used as the default for notifications that specify DEFAULT_VIBRATE. --> @@ -1533,6 +1537,7 @@ <item>com.android.server.notification.ValidateNotificationPeople</item> <item>com.android.server.notification.PackagePriorityExtractor</item> <item>com.android.server.notification.NotificationIntrusivenessExtractor</item> + <item>com.android.server.notification.PackageVisibilityExtractor</item> </string-array> <!-- Flag indicating that this device does not rotate and will always remain in its default diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 5e76a87..4bf4531 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2146,7 +2146,7 @@ <public type="attr" name="windowExitTransition" /> <public type="attr" name="windowSharedElementEnterTransition" /> <public type="attr" name="windowSharedElementExitTransition" /> - <public type="attr" name="windowAllowExitTransitionOverlap" /> + <public type="attr" name="windowAllowReturnTransitionOverlap" /> <public type="attr" name="windowAllowEnterTransitionOverlap" /> <public type="attr" name="sessionService" /> <public type="attr" name="stackViewStyle" /> @@ -2235,7 +2235,7 @@ <public type="attr" name="launchTaskBehindTargetAnimation" /> <public type="attr" name="launchTaskBehindSourceAnimation" /> <public type="attr" name="restrictionType" /> - <public type="attr" name="dayOfWeekBackgroundColor" /> + <public type="attr" name="dayOfWeekBackground" /> <public type="attr" name="dayOfWeekTextAppearance" /> <public type="attr" name="headerMonthTextAppearance" /> <public type="attr" name="headerDayOfMonthTextAppearance" /> @@ -2248,7 +2248,7 @@ <public type="attr" name="timePickerDialogTheme" /> <public type="attr" name="headerTimeTextAppearance" /> <public type="attr" name="headerAmPmTextAppearance" /> - <public type="attr" name="headerBackgroundColor" /> + <public type="attr" name="__removed2" /> <public type="attr" name="numbersTextColor" /> <public type="attr" name="numbersBackgroundColor" /> <public type="attr" name="numbersSelectorColor" /> @@ -2282,6 +2282,14 @@ <public type="attr" name="spotShadowAlpha" /> <public type="attr" name="navigationIcon" /> <public type="attr" name="navigationContentDescription" /> + <public type="attr" name="fragmentExitTransition" /> + <public type="attr" name="fragmentEnterTransition" /> + <public type="attr" name="fragmentSharedElementEnterTransition" /> + <public type="attr" name="fragmentReturnTransition" /> + <public type="attr" name="fragmentSharedElementReturnTransition" /> + <public type="attr" name="fragmentReenterTransition" /> + <public type="attr" name="fragmentAllowEnterTransitionOverlap" /> + <public type="attr" name="fragmentAllowReturnTransitionOverlap" /> <public-padding type="dimen" name="l_resource_pad" end="0x01050010" /> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 4aed037..c6d0b0b 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -62,6 +62,7 @@ please see styles_device_defaults.xml. <item name="centerMedium">@drawable/popup_center_medium</item> <item name="progressLayout">@layout/progress_dialog</item> <item name="horizontalProgressLayout">@layout/alert_dialog_progress</item> + <item name="needsDefaultBackgrounds">false</item> </style> <style name="Widget.PreferenceFrameLayout"> diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml index 2a54ccf..c7d2db1 100644 --- a/core/res/res/values/styles_holo.xml +++ b/core/res/res/values/styles_holo.xml @@ -468,7 +468,7 @@ please see styles_device_defaults.xml. <item name="internalLayout">@layout/time_picker_holo</item> <item name="headerTimeTextAppearance">@style/TextAppearance.Holo.TimePicker.TimeLabel</item> <item name="headerAmPmTextAppearance">@style/TextAppearance.Holo.TimePicker.AmPmLabel</item> - <item name="headerBackgroundColor">@color/timepicker_default_background_holo_dark</item> + <item name="headerBackground">@color/timepicker_default_background_holo_dark</item> <item name="headerSelectedTextColor">@color/holo_blue_light</item> <item name="numbersTextColor">@color/timepicker_default_text_color_holo_dark</item> <item name="numbersBackgroundColor">@color/timepicker_default_background_holo_dark</item> @@ -484,9 +484,9 @@ please see styles_device_defaults.xml. <item name="internalLayout">@layout/date_picker_holo</item> <item name="calendarViewShown">true</item> <!-- New-style date picker attributes. --> - <item name="dayOfWeekBackgroundColor">@color/datepicker_default_header_dayofweek_background_color_holo_dark</item> + <item name="dayOfWeekBackground">@color/datepicker_default_header_dayofweek_background_color_holo_dark</item> <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.DatePicker.DayOfWeekLabel</item> - <item name="headerBackgroundColor">@color/datepicker_default_header_selector_background_holo_dark</item> + <item name="headerBackground">@color/datepicker_default_header_selector_background_holo_dark</item> <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.MonthLabel</item> <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.DayOfMonthLabel</item> <item name="headerYearTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.YearLabel</item> @@ -892,7 +892,7 @@ please see styles_device_defaults.xml. <item name="internalLayout">@layout/time_picker_holo</item> <item name="headerTimeTextAppearance">@style/TextAppearance.Holo.Light.TimePicker.TimeLabel</item> <item name="headerAmPmTextAppearance">@style/TextAppearance.Holo.Light.TimePicker.AmPmLabel</item> - <item name="headerBackgroundColor">@color/timepicker_default_background_holo_light</item> + <item name="headerBackground">@color/timepicker_default_background_holo_light</item> <item name="headerSelectedTextColor">@color/holo_blue_light</item> <item name="numbersTextColor">@color/timepicker_default_text_color_holo_light</item> <item name="numbersBackgroundColor">@color/timepicker_default_background_holo_light</item> @@ -908,12 +908,12 @@ please see styles_device_defaults.xml. <item name="internalLayout">@layout/date_picker_holo</item> <item name="calendarViewShown">true</item> <!-- New-style date picker attributes. --> - <item name="dayOfWeekBackgroundColor">@color/datepicker_default_header_dayofweek_background_color_holo_light</item> + <item name="dayOfWeekBackground">@color/datepicker_default_header_dayofweek_background_color_holo_light</item> <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.DayOfWeekLabel</item> <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.MonthLabel</item> <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.DayOfMonthLabel</item> <item name="headerYearTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.YearLabel</item> - <item name="headerBackgroundColor">@color/datepicker_default_header_selector_background_holo_light</item> + <item name="headerBackground">@color/datepicker_default_header_selector_background_holo_light</item> <item name="headerSelectedTextColor">@color/holo_blue_light</item> <item name="yearListItemTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.List.YearLabel</item> <item name="yearListSelectorColor">@color/datepicker_default_circle_background_color_holo_light</item> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 8b3cbaf..a7335af 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -619,7 +619,7 @@ please see styles_device_defaults.xml. <item name="headerTimeTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item> <item name="headerAmPmTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item> <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item> - <item name="headerBackgroundColor">?attr/colorAccent</item> + <item name="headerBackground">@drawable/time_picker_header_material</item> <item name="numbersTextColor">?attr/textColorSecondary</item> <item name="numbersBackgroundColor">#10ffffff</item> <item name="amPmTextColor">?attr/textColorSecondary</item> @@ -634,13 +634,13 @@ please see styles_device_defaults.xml. <!-- Attributes for new-style DatePicker. --> <item name="internalLayout">@layout/date_picker_holo</item> <item name="calendarViewShown">true</item> - <item name="dayOfWeekBackgroundColor">#10000000</item> + <item name="dayOfWeekBackground">#10000000</item> <item name="dayOfWeekTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item> <item name="headerMonthTextAppearance">@style/TextAppearance.Material.DatePicker.MonthLabel</item> <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfMonthLabel</item> <item name="headerYearTextAppearance">@style/TextAppearance.Material.DatePicker.YearLabel</item> <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item> - <item name="headerBackgroundColor">?attr/colorAccent</item> + <item name="headerBackground">?attr/colorAccent</item> <item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item> <item name="yearListSelectorColor">?attr/colorControlActivated</item> <item name="calendarTextColor">?attr/textColorSecondary</item> @@ -838,7 +838,7 @@ please see styles_device_defaults.xml. </style> <style name="Widget.Material.ActionButton.CloseMode"> - <item name="background">@drawable/btn_cab_done_material</item> + <item name="background">?attr/selectableItemBackgroundBorderless</item> </style> <style name="Widget.Material.ActionButton.Overflow"> @@ -901,6 +901,7 @@ please see styles_device_defaults.xml. <style name="Widget.Material.ActionMode" parent="Widget.ActionMode"> <item name="titleTextStyle">@style/TextAppearance.Material.Widget.ActionMode.Title</item> <item name="subtitleTextStyle">@style/TextAppearance.Material.Widget.ActionMode.Subtitle</item> + <item name="closeItemLayout">@layout/action_mode_close_item_material</item> </style> <style name="Widget.Material.FastScroll" parent="Widget.FastScroll"> @@ -1068,16 +1069,16 @@ please see styles_device_defaults.xml. <!-- Dialog styles --> <style name="AlertDialog.Material" parent="AlertDialog"> - <item name="fullDark">@color/transparent</item> - <item name="topDark">@color/transparent</item> - <item name="centerDark">@color/transparent</item> - <item name="bottomDark">@color/transparent</item> - <item name="fullBright">@color/transparent</item> - <item name="topBright">@color/transparent</item> - <item name="centerBright">@color/transparent</item> - <item name="bottomBright">@color/transparent</item> - <item name="bottomMedium">@color/transparent</item> - <item name="centerMedium">@color/transparent</item> + <item name="fullDark">@null</item> + <item name="topDark">@null</item> + <item name="centerDark">@null</item> + <item name="bottomDark">@null</item> + <item name="fullBright">@null</item> + <item name="topBright">@null</item> + <item name="centerBright">@null</item> + <item name="bottomBright">@null</item> + <item name="bottomMedium">@null</item> + <item name="centerMedium">@null</item> <item name="layout">@layout/alert_dialog_material</item> <item name="listLayout">@layout/select_dialog_material</item> <item name="progressLayout">@layout/progress_dialog_material</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 06bd2ec..1b0f9c4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -283,6 +283,7 @@ <java-symbol type="bool" name="config_camera_sound_forced" /> <java-symbol type="bool" name="config_dontPreferApn" /> <java-symbol type="bool" name="config_restartRadioAfterProvisioning" /> + <java-symbol type="bool" name="config_requireRadioPowerOffOnSimRefreshReset" /> <java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" /> <java-symbol type="bool" name="config_useFixedVolume" /> <java-symbol type="bool" name="config_forceDefaultOrientation" /> @@ -2000,4 +2001,5 @@ <java-symbol type="id" name="parentMatrix" /> <java-symbol type="bool" name="config_auto_attach_data_on_creation" /> <java-symbol type="id" name="date_picker_month_day_year_layout" /> + <java-symbol type="attr" name="closeItemLayout" /> </resources> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 2296a12..ab5cd5a 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -306,7 +306,7 @@ please see themes_device_defaults.xml. <item name="actionOverflowMenuStyle">@style/Widget.Material.PopupMenu.Overflow</item> <item name="actionModeBackground">@drawable/cab_background_top_material</item> <item name="actionModeSplitBackground">@drawable/cab_background_bottom_material</item> - <item name="actionModeCloseDrawable">@drawable/ic_cab_done_material</item> + <item name="actionModeCloseDrawable">@drawable/ic_ab_back_material</item> <item name="actionBarTabStyle">@style/Widget.Material.ActionBar.TabView</item> <item name="actionBarTabBarStyle">@style/Widget.Material.ActionBar.TabBar</item> <item name="actionBarTabTextStyle">@style/Widget.Material.ActionBar.TabText</item> @@ -652,7 +652,7 @@ please see themes_device_defaults.xml. <item name="actionOverflowMenuStyle">@style/Widget.Material.Light.PopupMenu.Overflow</item> <item name="actionModeBackground">@drawable/cab_background_top_material</item> <item name="actionModeSplitBackground">@drawable/cab_background_bottom_material</item> - <item name="actionModeCloseDrawable">@drawable/ic_cab_done_material</item> + <item name="actionModeCloseDrawable">@drawable/ic_ab_back_material</item> <item name="actionBarTabStyle">@style/Widget.Material.Light.ActionBar.TabView</item> <item name="actionBarTabBarStyle">@style/Widget.Material.Light.ActionBar.TabBar</item> <item name="actionBarTabTextStyle">@style/Widget.Material.Light.ActionBar.TabText</item> diff --git a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml deleted file mode 100644 index ce6eebc..0000000 --- a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <accesspoint> - <ssid>opennet</ssid> - <security>NONE</security> - </accesspoint> - <accesspoint> - <ssid>GoogleGuest</ssid> - <security>NONE</security> - </accesspoint> - <accesspoint> - <ssid>securenetdhcp</ssid> - <security>PSK</security> - <password>androidwifi</password> - </accesspoint> - <accesspoint> - <ssid>securenetstatic</ssid> - <security>PSK</security> - <password>androidwifi</password> - <ip>192.168.14.2</ip> - <gateway>192.168.14.1</gateway> - <networkprefixlength>24</networkprefixlength> - <dns1>192.168.14.1</dns1> - <dns2>192.168.1.9</dns2> - </accesspoint> -<!-- TODO: This AP is outdated and only supports 2.4GHz. - Need to switch to a new dual-band AP. - Enable this test case again once the configuration is completed. - bug#: 9470594 - <accesspoint> - <ssid>botnet</ssid> - <security>EAP</security> - <eap>PEAP</eap> - <phase2>MSCHAPV2</phase2> - <identity>donut</identity> - <password>android</password> - </accesspoint> ---> -</resources> - diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java deleted file mode 100644 index 1222c8b..0000000 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2010, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.connectivitymanagertest; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; -import android.net.LinkAddress; -import android.net.RouteInfo; -import android.net.StaticIpConfiguration; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.AuthAlgorithm; -import android.net.wifi.WifiConfiguration.KeyMgmt; -import android.net.wifi.WifiEnterpriseConfig; - -import java.io.InputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; - - -/** - * Help class to process configurations of access points saved in an XML file. - * The configurations of an access point is included in tag - * <accesspoint></accesspoint>. The supported configuration includes: ssid, - * security, eap, phase2, identity, password, anonymousidentity, cacert, usercert, - * in which each is included in the corresponding tags. Static IP setting is also supported. - * Tags that can be used include: ip, gateway, networkprefixlength, dns1, dns2. All access points - * have to be enclosed in tags of <resources></resources>. - * - * The following is a sample configuration file for an access point using EAP-PEAP with MSCHAP2. - * <resources> - * <accesspoint> - * <ssid>testnet</ssid> - * <security>EAP</security> - * <eap>PEAP</eap> - * <phase2>MSCHAP2</phase2> - * <identity>donut</identity</identity> - * <password>abcdefgh</password> - * </accesspoint> - * </resources> - * - * Note:ssid and security have to be the first two tags - * for static ip setting, tag "ip" should be listed before other fields: dns, gateway, - * networkprefixlength. - */ -public class AccessPointParserHelper { - static final int NONE = 0; - static final int WEP = 1; - static final int PSK = 2; - static final int EAP = 3; - - List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); - - private int getSecurityType (String security) { - if (security.equalsIgnoreCase("NONE")) { - return NONE; - } else if (security.equalsIgnoreCase("WEP")) { - return WEP; - } else if (security.equalsIgnoreCase("PSK")) { - return PSK; - } else if (security.equalsIgnoreCase("EAP")) { - return EAP; - } else { - return -1; - } - } - - private boolean validateEapValue(String value) { - if (value.equalsIgnoreCase("PEAP") || - value.equalsIgnoreCase("TLS") || - value.equalsIgnoreCase("TTLS")) { - return true; - } else { - return false; - } - } - - DefaultHandler mHandler = new DefaultHandler() { - - boolean ssid = false; - boolean security = false; - boolean password = false; - boolean ip = false; - boolean gateway = false; - boolean networkprefix = false; - boolean dns1 = false; - boolean dns2 = false; - boolean eap = false; - boolean phase2 = false; - boolean identity = false; - boolean anonymousidentity = false; - boolean cacert = false; - boolean usercert = false; - WifiConfiguration config = null; - int securityType = NONE; - StaticIpConfiguration mStaticIpConfiguration = null; - InetAddress mInetAddr = null; - - @Override - public void startElement(String uri, String localName, String tagName, - Attributes attributes) throws SAXException { - if (tagName.equalsIgnoreCase("accesspoint")) { - config = new WifiConfiguration(); - } - if (tagName.equalsIgnoreCase("ssid")) { - ssid = true; - } - if (tagName.equalsIgnoreCase("security")) { - security = true; - } - if (tagName.equalsIgnoreCase("password")) { - password = true; - } - if (tagName.equalsIgnoreCase("eap")) { - eap = true; - } - if (tagName.equalsIgnoreCase("phase2")) { - phase2 = true; - } - if (tagName.equalsIgnoreCase("identity")) { - identity = true; - } - if (tagName.equalsIgnoreCase("anonymousidentity")) { - anonymousidentity = true; - } - if (tagName.equalsIgnoreCase("cacert")) { - cacert = true; - } - if (tagName.equalsIgnoreCase("usercert")) { - usercert = true; - } - if (tagName.equalsIgnoreCase("ip")) { - mStaticIpConfiguration = new StaticIpConfiguration(); - ip = true; - } - if (tagName.equalsIgnoreCase("gateway")) { - gateway = true; - } - if (tagName.equalsIgnoreCase("networkprefixlength")) { - networkprefix = true; - } - if (tagName.equalsIgnoreCase("dns1")) { - dns1 = true; - } - if (tagName.equalsIgnoreCase("dns2")) { - dns2 = true; - } - } - - @Override - public void endElement(String uri, String localName, String tagName) throws SAXException { - if (tagName.equalsIgnoreCase("accesspoint")) { - if (mStaticIpConfiguration != null) { - config.setIpAssignment(IpAssignment.STATIC); - config.setStaticIpConfiguration(mStaticIpConfiguration); - } else { - config.setIpAssignment(IpAssignment.DHCP); - } - config.setProxySettings(ProxySettings.NONE); - networks.add(config); - mStaticIpConfiguration = null; - } - } - - @Override - public void characters(char ch[], int start, int length) throws SAXException { - if (ssid) { - config.SSID = new String(ch, start, length); - ssid = false; - } - if (security) { - String securityStr = (new String(ch, start, length)).toUpperCase(); - securityType = getSecurityType(securityStr); - switch (securityType) { - case NONE: - config.allowedKeyManagement.set(KeyMgmt.NONE); - break; - case WEP: - config.allowedKeyManagement.set(KeyMgmt.NONE); - config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); - config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); - break; - case PSK: - config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); - break; - case EAP: - config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); - config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); - // Initialize other fields. - config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE); - config.enterpriseConfig.setCaCertificateAlias(""); - config.enterpriseConfig.setClientCertificateAlias(""); - config.enterpriseConfig.setIdentity(""); - config.enterpriseConfig.setAnonymousIdentity(""); - break; - default: - throw new SAXException(); - } - security = false; - } - if (password) { - String passwordStr = new String(ch, start, length); - int len = passwordStr.length(); - if (len == 0) { - throw new SAXException(); - } - if (securityType == WEP) { - if ((len == 10 || len == 26 || len == 58) && - passwordStr.matches("[0-9A-Fa-f]*")) { - config.wepKeys[0] = passwordStr; - } else { - config.wepKeys[0] = '"' + passwordStr + '"'; - } - } else if (securityType == PSK) { - if (passwordStr.matches("[0-9A-Fa-f]{64}")) { - config.preSharedKey = passwordStr; - } else { - config.preSharedKey = '"' + passwordStr + '"'; - } - } else if (securityType == EAP) { - config.enterpriseConfig.setPassword(passwordStr); - } else { - throw new SAXException(); - } - password = false; - } - if (eap) { - String eapValue = new String(ch, start, length); - if (!validateEapValue(eapValue)) { - throw new SAXException(); - } - if (eapValue.equals("TLS")) { - config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS); - } else if (eapValue.equals("TTLS")) { - config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS); - } else if (eapValue.equals("PEAP")) { - config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PEAP); - } - eap = false; - } - if (phase2) { - String phase2Value = new String(ch, start, length); - if (phase2Value.equals("PAP")) { - config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.PAP); - } else if (phase2Value.equals("MSCHAP")) { - config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAP); - } else if (phase2Value.equals("MSCHAPV2")) { - config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAPV2); - } else if (phase2Value.equals("GTC")) { - config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC); - } - phase2 = false; - } - if (identity) { - String identityValue = new String(ch, start, length); - config.enterpriseConfig.setIdentity(identityValue); - identity = false; - } - if (anonymousidentity) { - String anonyId = new String(ch, start, length); - config.enterpriseConfig.setAnonymousIdentity(anonyId); - anonymousidentity = false; - } - if (cacert) { - String cacertValue = new String(ch, start, length); - config.enterpriseConfig.setCaCertificateAlias(cacertValue); - cacert = false; - } - if (usercert) { - String usercertValue = new String(ch, start, length); - config.enterpriseConfig.setClientCertificateAlias(usercertValue); - usercert = false; - } - if (ip) { - try { - String ipAddr = new String(ch, start, length); - if (!InetAddress.isNumeric(ipAddr)) { - throw new SAXException(); - } - mInetAddr = InetAddress.getByName(ipAddr); - } catch (UnknownHostException e) { - throw new SAXException(); - } - ip = false; - } - if (gateway) { - try { - String gwAddr = new String(ch, start, length); - if (!InetAddress.isNumeric(gwAddr)) { - throw new SAXException(); - } - mStaticIpConfiguration.gateway = InetAddress.getByName(gwAddr); - } catch (UnknownHostException e) { - throw new SAXException(); - } - gateway = false; - } - if (networkprefix) { - try { - int nwPrefixLength = Integer.parseInt(new String(ch, start, length)); - if ((nwPrefixLength < 0) || (nwPrefixLength > 32)) { - throw new SAXException(); - } - mStaticIpConfiguration.ipAddress = new LinkAddress(mInetAddr, nwPrefixLength); - } catch (NumberFormatException e) { - throw new SAXException(); - } - networkprefix = false; - } - if (dns1) { - try { - String dnsAddr = new String(ch, start, length); - if (!InetAddress.isNumeric(dnsAddr)) { - throw new SAXException(); - } - mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr)); - } catch (UnknownHostException e) { - throw new SAXException(); - } - dns1 = false; - } - if (dns2) { - try { - String dnsAddr = new String(ch, start, length); - if (!InetAddress.isNumeric(dnsAddr)) { - throw new SAXException(); - } - mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr)); - } catch (UnknownHostException e) { - throw new SAXException(); - } - dns2 = false; - } - } - }; - - /** - * Process the InputStream in - * @param in is the InputStream that can be used for XML parsing - * @throws Exception - */ - public AccessPointParserHelper(InputStream in) throws Exception { - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser saxParser = factory.newSAXParser(); - saxParser.parse(in, mHandler); - } - - public List<WifiConfiguration> getNetworkConfigurations() throws Exception { - return networks; - } -} diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java index 0f9d8e9..a3c5351 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java @@ -26,7 +26,6 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiManager; import android.os.PowerManager; import android.os.SystemClock; @@ -35,10 +34,8 @@ import android.util.Log; import android.view.KeyEvent; import java.io.IOException; -import java.io.InputStream; import java.net.UnknownHostException; import java.util.List; -import java.util.regex.Pattern; /** @@ -52,8 +49,6 @@ import java.util.regex.Pattern; */ public class ConnectivityManagerTestBase extends InstrumentationTestCase { - private static final String LOG_TAG = "ConnectivityManagerTestBase"; - private static final String ACCESS_POINT_FILE = "accesspoints.xml"; private static final String PING_IP_ADDR = "8.8.8.8"; protected static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds @@ -69,9 +64,10 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { protected static final int FAILURE = 1; protected static final int INIT = -1; + protected final String mLogTag; + private ConnectivityReceiver mConnectivityReceiver = null; private WifiReceiver mWifiReceiver = null; - private AccessPointParserHelper mParseHelper = null; private long mLastConnectivityChangeTime = -1; protected ConnectivityManager mCm; @@ -82,6 +78,11 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { /* Control Wifi States */ public WifiManager mWifiManager; + public ConnectivityManagerTestBase(String logTag) { + super(); + mLogTag = logTag; + } + protected long getLastConnectivityChangeTime() { return mLastConnectivityChangeTime; } @@ -94,7 +95,7 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { @Override public void onReceive(Context context, Intent intent) { mLastConnectivityChangeTime = SystemClock.uptimeMillis(); - log("ConnectivityReceiver: " + intent); + logv("ConnectivityReceiver: " + intent); String action = intent.getAction(); if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { Log.v("ConnectivityReceiver", "onReceive() called with " + intent); @@ -108,7 +109,7 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { String action = intent.getAction(); Log.v("WifiReceiver", "onReceive() is calleld with " + intent); if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - log("scan results are available"); + logv("scan results are available"); synchronized (mWifiScanResultLock) { mLastScanResult = mWifiManager.getScanResults(); mWifiScanResultLock.notifyAll(); @@ -130,7 +131,7 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { if (mWifiManager.isWifiApEnabled()) { // if soft AP is enabled, disable it mWifiManager.setWifiApEnabled(null, false); - log("Disable soft ap"); + logv("Disable soft ap"); } // register a connectivity receiver for CONNECTIVITY_ACTION; @@ -148,32 +149,25 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); mContext.registerReceiver(mWifiReceiver, mIntentFilter); - log("Clear Wifi before we start the test."); + logv("Clear Wifi before we start the test."); removeConfiguredNetworksAndDisableWifi(); } - protected List<WifiConfiguration> loadNetworkConfigurations() throws Exception { - InputStream in = mContext.getAssets().open(ACCESS_POINT_FILE); - mParseHelper = new AccessPointParserHelper(in); - return mParseHelper.getNetworkConfigurations(); - } - // wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, // DISCONNECTED, UNKNOWN protected boolean waitForNetworkState(int networkType, State expectedState, long timeout) { long startTime = SystemClock.uptimeMillis(); while (true) { NetworkInfo ni = mCm.getNetworkInfo(networkType); - String niString = ni == null ? "null" : ni.toString(); if (ni != null && expectedState.equals(ni.getState())) { - log("waitForNetworkState success: " + niString); + logv("waitForNetworkState success: %s", ni); return true; } if ((SystemClock.uptimeMillis() - startTime) > timeout) { - log("waitForNetworkState timeout: " + niString); + logv("waitForNetworkState timeout: %s", ni); return false; } - log("waitForNetworkState interim: " + niString); + logv("waitForNetworkState interim: %s", ni); SystemClock.sleep(SHORT_TIMEOUT); } } @@ -185,16 +179,14 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { while (true) { int state = mWifiManager.getWifiState(); if (state == expectedState) { - log("waitForWifiState success: state=" + state); + logv("waitForWifiState success: state=" + state); return true; } if ((SystemClock.uptimeMillis() - startTime) > timeout) { - log(String.format("waitForWifiState timeout: expected=%d, actual=%d", - expectedState, state)); + logv("waitForWifiState timeout: expected=%d, actual=%d", expectedState, state); return false; } - log(String.format("waitForWifiState interim: expected=%d, actual=%d", - expectedState, state)); + logv("waitForWifiState interim: expected=%d, actual=%d", expectedState, state); SystemClock.sleep(SHORT_TIMEOUT); } } @@ -206,15 +198,15 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { while (true) { int state = mWifiManager.getWifiApState(); if (state == expectedState) { - log("waitForWifiAPState success: state=" + state); + logv("waitForWifiAPState success: state=" + state); return true; } if ((SystemClock.uptimeMillis() - startTime) > timeout) { - log(String.format("waitForWifiAPState timeout: expected=%d, actual=%d", + logv(String.format("waitForWifiAPState timeout: expected=%d, actual=%d", expectedState, state)); return false; } - log(String.format("waitForWifiAPState interim: expected=%d, actual=%d", + logv(String.format("waitForWifiAPState interim: expected=%d, actual=%d", expectedState, state)); SystemClock.sleep(SHORT_TIMEOUT); } @@ -269,7 +261,7 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { // Turn screen off protected void turnScreenOff() { - log("Turn screen off"); + logv("Turn screen off"); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); pm.goToSleep(SystemClock.uptimeMillis()); @@ -277,7 +269,7 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { // Turn screen on protected void turnScreenOn() { - log("Turn screen on"); + logv("Turn screen on"); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); pm.wakeUp(SystemClock.uptimeMillis()); @@ -305,7 +297,7 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { // assume the chance that all servers are down is very small for (int i = 0; i < hostList.length; i++ ) { String host = hostList[i]; - log("Start ping test, ping " + host); + logv("Start ping test, ping " + host); Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host); int status = p.waitFor(); if (status == 0) { @@ -314,11 +306,11 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { } } } catch (UnknownHostException e) { - log("Ping test Fail: Unknown Host"); + logv("Ping test Fail: Unknown Host"); } catch (IOException e) { - log("Ping test Fail: IOException"); + logv("Ping test Fail: IOException"); } catch (InterruptedException e) { - log("Ping test Fail: InterruptedException"); + logv("Ping test Fail: InterruptedException"); } } // ping test timeout @@ -331,29 +323,22 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { * We don't verify whether the connection is successful or not, leave this to the test */ protected boolean connectToWifi(String knownSSID) { - WifiConfiguration config = new WifiConfiguration(); - config.SSID = knownSSID; - config.allowedKeyManagement.set(KeyMgmt.NONE); + WifiConfiguration config = WifiConfigurationHelper.createOpenConfig(knownSSID); return connectToWifiWithConfiguration(config); } /** * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration * is pure string, we need to convert it to quoted string. - * @param config - * @return */ protected boolean connectToWifiWithConfiguration(WifiConfiguration config) { - String ssid = config.SSID; - config.SSID = convertToQuotedString(ssid); - // If Wifi is not enabled, enable it if (!mWifiManager.isWifiEnabled()) { - log("Wifi is not enabled, enable it"); + logv("Wifi is not enabled, enable it"); mWifiManager.setWifiEnabled(true); // wait for the wifi state change before start scanning. if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT)) { - log("wait for WIFI_STATE_ENABLED failed"); + logv("wait for WIFI_STATE_ENABLED failed"); return false; } } @@ -361,10 +346,13 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { // Save network configuration and connect to network without scanning mWifiManager.connect(config, new WifiManager.ActionListener() { + @Override public void onSuccess() { } + + @Override public void onFailure(int reason) { - log("connect failure " + reason); + logv("connect failure " + reason); } }); return true; @@ -376,25 +364,28 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { protected boolean disconnectAP() { // remove saved networks if (!mWifiManager.isWifiEnabled()) { - log("Enabled wifi before remove configured networks"); + logv("Enabled wifi before remove configured networks"); mWifiManager.setWifiEnabled(true); SystemClock.sleep(SHORT_TIMEOUT); } List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks(); if (wifiConfigList == null) { - log("no configuration list is null"); + logv("no configuration list is null"); return true; } - log("size of wifiConfigList: " + wifiConfigList.size()); + logv("size of wifiConfigList: " + wifiConfigList.size()); for (WifiConfiguration wifiConfig: wifiConfigList) { - log("remove wifi configuration: " + wifiConfig.networkId); + logv("remove wifi configuration: " + wifiConfig.networkId); int netId = wifiConfig.networkId; mWifiManager.forget(netId, new WifiManager.ActionListener() { + @Override public void onSuccess() { } + + @Override public void onFailure(int reason) { - log("Failed to forget " + reason); + logv("Failed to forget " + reason); } }); } @@ -431,15 +422,14 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { long startTime = SystemClock.uptimeMillis(); while (true) { NetworkInfo ni = mCm.getActiveNetworkInfo(); - String niString = ni == null ? "null" : ni.toString(); if (ni != null && ni.isConnected()) { return true; } if ((SystemClock.uptimeMillis() - startTime) > timeout) { - log("waitForActiveNetworkConnection timeout: " + niString); + logv("waitForActiveNetworkConnection timeout: %s", ni); return false; } - log("waitForActiveNetworkConnection interim: " + niString); + logv("waitForActiveNetworkConnection interim: %s", ni); SystemClock.sleep(SHORT_TIMEOUT); } } @@ -451,12 +441,11 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { if (ni == null) { return true; } - String niString = ni.toString(); if ((SystemClock.uptimeMillis() - startTime) > timeout) { - log("waitForActiveNetworkConnection timeout: " + niString); + logv("waitForActiveNetworkConnection timeout: %s", ni); return false; } - log("waitForActiveNetworkConnection interim: " + niString); + logv("waitForActiveNetworkConnection interim: %s", ni); SystemClock.sleep(SHORT_TIMEOUT); } } @@ -467,12 +456,9 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { try { Process proc = Runtime.getRuntime().exec(new String[]{ "/system/bin/ping", "-W", "30", "-c", "1", PING_IP_ADDR}); - int exitCode = proc.waitFor(); - return exitCode == 0; - } catch (InterruptedException ie) { - Log.e(LOG_TAG, "InterruptedException while waiting for ping"); - } catch (IOException ioe) { - Log.e(LOG_TAG, "IOException during ping", ioe); + return proc.waitFor() == 0; + } catch (InterruptedException | IOException e) { + Log.e(mLogTag, "Ping failed", e); } return false; } @@ -489,8 +475,8 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { super.tearDown(); } - private void log(String message) { - Log.v(LOG_TAG, message); + protected void logv(String format, Object... args) { + Log.v(mLogTag, String.format(format, args)); } /** @@ -506,22 +492,10 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { // step 2: verify Wifi state and network state; assertTrue("wifi state not connected with " + config.SSID, waitForNetworkState(ConnectivityManager.TYPE_WIFI, - State.CONNECTED, LONG_TIMEOUT)); + State.CONNECTED, WIFI_CONNECTION_TIMEOUT)); // step 3: verify the current connected network is the given SSID assertNotNull("no active wifi info", mWifiManager.getConnectionInfo()); assertEquals("SSID mismatch", config.SSID, mWifiManager.getConnectionInfo().getSSID()); } - - /** - * checks if the input is a hexadecimal string of given length - * - * @param input string to be checked - * @param length required length of the string - * @return - */ - protected static boolean isHex(String input, int length) { - Pattern p = Pattern.compile(String.format("[0-9A-Fa-f]{%d}", length)); - return p.matcher(input).matches(); - } } diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java new file mode 100644 index 0000000..f0a8367 --- /dev/null +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2010, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.connectivitymanagertest; + +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.StaticIpConfiguration; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.AuthAlgorithm; +import android.net.wifi.WifiConfiguration.KeyMgmt; +import android.net.wifi.WifiEnterpriseConfig; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +/** + * Helper for dealing with creating {@link WifiConfiguration} objects. + */ +public class WifiConfigurationHelper { + private static final int NONE = 0; + private static final int WEP = 1; + private static final int PSK = 2; + private static final int EAP = 3; + + /** + * Private constructor since this a static class. + */ + private WifiConfigurationHelper() {} + + /** + * Create a {@link WifiConfiguration} for an open network + * + * @param ssid The SSID of the wifi network + * @return The {@link WifiConfiguration} + */ + public static WifiConfiguration createOpenConfig(String ssid) { + WifiConfiguration config = createGenericConfig(ssid); + + config.allowedKeyManagement.set(KeyMgmt.NONE); + return config; + } + + /** + * Create a {@link WifiConfiguration} for a WEP secured network + * + * @param ssid The SSID of the wifi network + * @param password Either a 10, 26, or 58 character hex string or the plain text password + * @return The {@link WifiConfiguration} + */ + public static WifiConfiguration createWepConfig(String ssid, String password) { + WifiConfiguration config = createGenericConfig(ssid); + + if (isHex(password, 10) || isHex(password, 26) || isHex(password, 58)) { + config.wepKeys[0] = password; + } else { + config.wepKeys[0] = quotedString(password); + } + + config.allowedKeyManagement.set(KeyMgmt.NONE); + config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); + config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); + return config; + } + + /** + * Create a {@link WifiConfiguration} for a PSK secured network + * + * @param ssid The SSID of the wifi network + * @param password Either a 64 character hex string or the plain text password + * @return The {@link WifiConfiguration} + */ + public static WifiConfiguration createPskConfig(String ssid, String password) { + WifiConfiguration config = createGenericConfig(ssid); + + if (isHex(password, 64)) { + config.preSharedKey = password; + } else { + config.preSharedKey = quotedString(password); + } + config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); + return config; + } + + /** + * Create a {@link WifiConfiguration} for an EAP secured network + * + * @param ssid The SSID of the wifi network + * @param password The password + * @param eapMethod The EAP method + * @param phase2 The phase 2 method or null + * @param identity The identity or null + * @param anonymousIdentity The anonymous identity or null + * @param caCert The CA certificate or null + * @param clientCert The client certificate or null + * @return The {@link WifiConfiguration} + */ + public static WifiConfiguration createEapConfig(String ssid, String password, int eapMethod, + Integer phase2, String identity, String anonymousIdentity, String caCert, + String clientCert) { + WifiConfiguration config = new WifiConfiguration(); + config.SSID = quotedString(ssid); + + config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); + config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); + + // Set defaults + if (phase2 == null) phase2 = WifiEnterpriseConfig.Phase2.NONE; + if (identity == null) identity = ""; + if (anonymousIdentity == null) anonymousIdentity = ""; + if (caCert == null) caCert = ""; + if (clientCert == null) clientCert = ""; + + config.enterpriseConfig.setPassword(password); + config.enterpriseConfig.setEapMethod(eapMethod); + config.enterpriseConfig.setPhase2Method(phase2); + config.enterpriseConfig.setIdentity(identity); + config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity); + config.enterpriseConfig.setCaCertificateAlias(caCert); + config.enterpriseConfig.setClientCertificateAlias(clientCert); + return config; + } + + /** + * Create a generic {@link WifiConfiguration} used by the other create methods. + */ + private static WifiConfiguration createGenericConfig(String ssid) { + WifiConfiguration config = new WifiConfiguration(); + config.SSID = quotedString(ssid); + config.setIpAssignment(IpAssignment.DHCP); + config.setProxySettings(ProxySettings.NONE); + return config; + } + + /** + * Parse a JSON string for WiFi configurations stored as a JSON string. + * <p> + * This json string should be a list of dictionaries, with each dictionary containing a single + * wifi configuration. The wifi configuration requires the fields "ssid" and "security" with + * security being one of NONE, WEP, PSK, or EAP. If WEP, PSK, or EAP are selected, the field + * "password" must also be provided. If EAP is selected, then the fiels "eap", "phase2", + * "identity", "ananymous_identity", "ca_cert", and "client_cert" are also required. Lastly, + * static IP settings are also supported. If the field "ip" is set, then the fields "gateway", + * "prefix_length", "dns1", and "dns2" are required. + * </p> + * @throws IllegalArgumentException if the input string was not valid JSON or if any mandatory + * fields are missing. + */ + public static List<WifiConfiguration> parseJson(String in) { + try { + JSONArray jsonConfigs = new JSONArray(in); + List<WifiConfiguration> wifiConfigs = new ArrayList<>(jsonConfigs.length()); + + for (int i = 0; i < jsonConfigs.length(); i++) { + JSONObject jsonConfig = jsonConfigs.getJSONObject(i); + + wifiConfigs.add(getWifiConfiguration(jsonConfig)); + } + return wifiConfigs; + } catch (JSONException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Parse a {@link JSONObject} and return the wifi configuration. + * + * @throws IllegalArgumentException if any mandatory fields are missing. + */ + private static WifiConfiguration getWifiConfiguration(JSONObject jsonConfig) + throws JSONException { + String ssid = jsonConfig.getString("ssid"); + String password = null; + WifiConfiguration config; + + int securityType = getSecurityType(jsonConfig.getString("security")); + switch (securityType) { + case NONE: + config = createOpenConfig(ssid); + break; + case WEP: + password = jsonConfig.getString("password"); + config = createWepConfig(ssid, password); + break; + case PSK: + password = jsonConfig.getString("password"); + config = createPskConfig(ssid, password); + break; + case EAP: + password = jsonConfig.getString("password"); + int eapMethod = getEapMethod(jsonConfig.getString("eap")); + Integer phase2 = null; + if (jsonConfig.has("phase2")) { + phase2 = getPhase2(jsonConfig.getString("phase2")); + } + String identity = null; + if (jsonConfig.has("identity")) { + identity = jsonConfig.getString("identity"); + } + String anonymousIdentity = null; + if (jsonConfig.has("anonymous_identity")) { + anonymousIdentity = jsonConfig.getString("anonymous_identity"); + } + String caCert = null; + if (jsonConfig.has("ca_cert")) { + caCert = (jsonConfig.getString("ca_cert")); + } + String clientCert = null; + if (jsonConfig.has("client_cert")) { + clientCert = jsonConfig.getString("client_cert"); + } + config = createEapConfig(ssid, password, eapMethod, phase2, identity, + anonymousIdentity, caCert, clientCert); + break; + default: + // Should never reach here as getSecurityType will already throw an exception + throw new IllegalArgumentException(); + } + + if (jsonConfig.has("ip")) { + StaticIpConfiguration staticIpConfig = new StaticIpConfiguration(); + + InetAddress ipAddress = getInetAddress(jsonConfig.getString("ip")); + int prefixLength = getPrefixLength(jsonConfig.getInt("prefix_length")); + staticIpConfig.ipAddress = new LinkAddress(ipAddress, prefixLength); + staticIpConfig.gateway = getInetAddress(jsonConfig.getString("gateway")); + staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns1"))); + staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns2"))); + + config.setIpAssignment(IpAssignment.STATIC); + config.setStaticIpConfiguration(staticIpConfig); + } else { + config.setIpAssignment(IpAssignment.DHCP); + } + + config.setProxySettings(ProxySettings.NONE); + return config; + } + + private static String quotedString(String s) { + return String.format("\"%s\"", s); + } + + /** + * Get the security type from a string. + * + * @throws IllegalArgumentException if the string is not a supported security type. + */ + private static int getSecurityType(String security) { + if ("NONE".equalsIgnoreCase(security)) { + return NONE; + } + if ("WEP".equalsIgnoreCase(security)) { + return WEP; + } + if ("PSK".equalsIgnoreCase(security)) { + return PSK; + } + if ("EAP".equalsIgnoreCase(security)) { + return EAP; + } + throw new IllegalArgumentException("Security type must be one of NONE, WEP, PSK, or EAP"); + } + + /** + * Get the EAP method from a string. + * + * @throws IllegalArgumentException if the string is not a supported EAP method. + */ + private static int getEapMethod(String eapMethod) { + if ("TLS".equalsIgnoreCase(eapMethod)) { + return WifiEnterpriseConfig.Eap.TLS; + } + if ("TTLS".equalsIgnoreCase(eapMethod)) { + return WifiEnterpriseConfig.Eap.TTLS; + } + if ("PEAP".equalsIgnoreCase(eapMethod)) { + return WifiEnterpriseConfig.Eap.PEAP; + } + throw new IllegalArgumentException("EAP method must be one of TLS, TTLS, or PEAP"); + } + + /** + * Get the phase 2 method from a string. + * + * @throws IllegalArgumentException if the string is not a supported phase 2 method. + */ + private static int getPhase2(String phase2) { + if ("PAP".equalsIgnoreCase(phase2)) { + return WifiEnterpriseConfig.Phase2.PAP; + } + if ("MSCHAP".equalsIgnoreCase(phase2)) { + return WifiEnterpriseConfig.Phase2.MSCHAP; + } + if ("MSCHAPV2".equalsIgnoreCase(phase2)) { + return WifiEnterpriseConfig.Phase2.MSCHAPV2; + } + if ("GTC".equalsIgnoreCase(phase2)) { + return WifiEnterpriseConfig.Phase2.GTC; + } + throw new IllegalArgumentException("Phase2 must be one of PAP, MSCHAP, MSCHAPV2, or GTC"); + } + + /** + * Get an {@link InetAddress} from a string + * + * @throws IllegalArgumentException if the string is not a valid IP address. + */ + private static InetAddress getInetAddress(String ipAddress) { + if (!InetAddress.isNumeric(ipAddress)) { + throw new IllegalArgumentException( + String.format("IP address %s is not numeric", ipAddress)); + } + + try { + return InetAddress.getByName(ipAddress); + } catch (UnknownHostException e) { + throw new IllegalArgumentException( + String.format("IP address %s could not be resolved", ipAddress)); + } + } + + /** + * Get the prefix length from an int. + * + * @throws IllegalArgumentException if the prefix length is less than 0 or greater than 32. + */ + private static int getPrefixLength(int prefixLength) { + if (prefixLength < 0 || prefixLength > 32) { + throw new IllegalArgumentException("Prefix length cannot be less than 0 or more than 32"); + } + return prefixLength; + } + + /** + * Utility method to check if a given string is a hexadecimal string of given length + */ + public static boolean isHex(String input, int length) { + if (input == null || length < 0) { + return false; + } + return input.matches(String.format("[0-9A-Fa-f]{%d}", length)); + } +} diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java index 01995c7..b280106 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java @@ -23,14 +23,15 @@ import android.net.wifi.WifiManager; import android.os.SystemClock; import android.provider.Settings; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; import com.android.connectivitymanagertest.ConnectivityManagerTestBase; import com.android.connectivitymanagertest.ConnectivityManagerTestRunner; -public class ConnectivityManagerMobileTest extends - ConnectivityManagerTestBase { - private static final String TAG = "ConnectivityManagerMobileTest"; +public class ConnectivityManagerMobileTest extends ConnectivityManagerTestBase { + + public ConnectivityManagerMobileTest() { + super(ConnectivityManagerMobileTest.class.getSimpleName()); + } private String mTestAccessPoint; private boolean mWifiOnlyFlag; @@ -46,7 +47,7 @@ public class ConnectivityManagerMobileTest extends // Each test case will start with cellular connection if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(), Settings.Global.AIRPLANE_MODE_ON) == 1) { - log("airplane is not disabled, disable it."); + logv("airplane is not disabled, disable it."); mCm.setAirplaneMode(false); } @@ -77,16 +78,14 @@ public class ConnectivityManagerMobileTest extends assertTrue("not connected to cellular network", extraNetInfo.isConnected()); } - private void log(String message) { - Log.v(TAG, message); - } + // Test case 1: Test enabling Wifi without associating with any AP, no broadcast on network // event should be expected. @LargeTest public void test3GToWifiNotification() { if (mWifiOnlyFlag) { - Log.v(TAG, getName() + " is excluded for wifi-only test"); + logv(getName() + " is excluded for wifi-only test"); return; } @@ -225,7 +224,7 @@ public class ConnectivityManagerMobileTest extends @LargeTest public void testDataConnectionWith3GToAmTo3G() { if (mWifiOnlyFlag) { - Log.v(TAG, getName() + " is excluded for wifi-only test"); + logv(getName() + " is excluded for wifi-only test"); return; } // disable wifi diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java index eb75b0d..c2b80dc 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java @@ -21,16 +21,15 @@ import android.net.NetworkInfo.State; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.AuthAlgorithm; import android.net.wifi.WifiConfiguration.GroupCipher; -import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiConfiguration.PairwiseCipher; import android.net.wifi.WifiConfiguration.Protocol; import android.net.wifi.WifiInfo; import android.os.Bundle; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; import com.android.connectivitymanagertest.ConnectivityManagerTestBase; import com.android.connectivitymanagertest.WifiAssociationTestRunner; +import com.android.connectivitymanagertest.WifiConfigurationHelper; /** * Test Wi-Fi connection with different configuration @@ -40,7 +39,6 @@ import com.android.connectivitymanagertest.WifiAssociationTestRunner; * -w com.android.connectivitymanagertest/.WifiAssociationTestRunner" */ public class WifiAssociationTest extends ConnectivityManagerTestBase { - private static final String TAG = "WifiAssociationTest"; private String mSsid = null; private String mPassword = null; private String mSecurityType = null; @@ -51,6 +49,10 @@ public class WifiAssociationTest extends ConnectivityManagerTestBase { OPEN, WEP64, WEP128, WPA_TKIP, WPA2_AES } + public WifiAssociationTest() { + super(WifiAssociationTest.class.getSimpleName()); + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -77,90 +79,58 @@ public class WifiAssociationTest extends ConnectivityManagerTestBase { private void validateFrequencyBand() { if (mFrequencyBand != null) { int currentFreq = mWifiManager.getFrequencyBand(); - Log.v(TAG, "read frequency band: " + currentFreq); + logv("read frequency band: " + currentFreq); assertEquals("specified frequency band does not match operational band of WifiManager", currentFreq, mBand); } } - private void log(String message) { - Log.v(TAG, message); - } - @LargeTest public void testWifiAssociation() { assertNotNull("no test ssid", mSsid); - WifiConfiguration config = new WifiConfiguration(); - config.SSID = mSsid; + WifiConfiguration config = null; SECURITY_TYPE security = SECURITY_TYPE.valueOf(mSecurityType); - log("Security type is " + security.toString()); + logv("Security type is " + security.toString()); switch (security) { // set network configurations case OPEN: - config.allowedKeyManagement.set(KeyMgmt.NONE); + config = WifiConfigurationHelper.createOpenConfig(mSsid); break; case WEP64: assertNotNull("password is empty", mPassword); - config.allowedKeyManagement.set(KeyMgmt.NONE); - config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); - config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); + // always use hex pair for WEP-40 + assertTrue(WifiConfigurationHelper.isHex(mPassword, 10)); + config = WifiConfigurationHelper.createWepConfig(mSsid, mPassword); config.allowedGroupCiphers.set(GroupCipher.WEP40); - if (mPassword != null) { - // always use hex pair for WEP-40 - if (isHex(mPassword, 10)) { - config.wepKeys[0] = mPassword; - } else { - fail("password should be 10-character hex"); - } - } break; case WEP128: assertNotNull("password is empty", mPassword); - config.allowedKeyManagement.set(KeyMgmt.NONE); - config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); - config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); + // always use hex pair for WEP-104 + assertTrue(WifiConfigurationHelper.isHex(mPassword, 26)); + config = WifiConfigurationHelper.createWepConfig(mSsid, mPassword); config.allowedGroupCiphers.set(GroupCipher.WEP104); - if (mPassword != null) { - // always use hex pair for WEP-104 - if (isHex(mPassword, 26)) { - config.wepKeys[0] = mPassword; - } else { - fail("password should be 26-character hex"); - } - } break; case WPA_TKIP: assertNotNull("password is empty", mPassword); - config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); + config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword); config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); config.allowedProtocols.set(Protocol.WPA); config.allowedPairwiseCiphers.set(PairwiseCipher.TKIP); config.allowedGroupCiphers.set(GroupCipher.TKIP); - if (isHex(mPassword, 64)) { - config.preSharedKey = mPassword; - } else { - config.preSharedKey = '"' + mPassword + '"'; - } break; case WPA2_AES: assertNotNull("password is empty", mPassword); - config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); + config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword); config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); config.allowedProtocols.set(Protocol.RSN); config.allowedPairwiseCiphers.set(PairwiseCipher.CCMP); config.allowedGroupCiphers.set(GroupCipher.CCMP); - config.allowedProtocols.set(Protocol.RSN); - if (isHex(mPassword, 64)) { - config.preSharedKey = mPassword; - } else { - config.preSharedKey = '"' + mPassword + '"'; - } break; default: fail("Not a valid security type: " + mSecurityType); break; } - Log.v(TAG, "network config: " + config.toString()); + logv("network config: %s", config.toString()); connectToWifi(config); // verify that connection actually works assertTrue("no network connectivity at end of test", checkNetworkConnectivity()); diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java index 740ffb8..b37daa3 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java @@ -16,54 +16,38 @@ package com.android.connectivitymanagertest.functional; -import android.net.ConnectivityManager; -import android.net.NetworkInfo.State; import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; +import android.os.SystemClock; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; import com.android.connectivitymanagertest.ConnectivityManagerTestBase; +import com.android.connectivitymanagertest.WifiConfigurationHelper; -import java.util.ArrayList; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; import java.util.List; /** * Test Wi-Fi connection with different configuration * To run this tests: - * adb shell am instrument -e class - * com.android.connectivitymanagertest.functional.WifiConnectionTest - * -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner + * adb shell am instrument \ + * -e class com.android.connectivitymanagertest.functional.WifiConnectionTest \ + * -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner */ -public class WifiConnectionTest - extends ConnectivityManagerTestBase { - private static final String TAG = "WifiConnectionTest"; - private static final boolean DEBUG = false; - private List<WifiConfiguration> mNetworks = new ArrayList<WifiConfiguration>(); +public class WifiConnectionTest extends ConnectivityManagerTestBase { + private static final String WIFI_CONFIG_FILE = "/data/wifi_configs.json"; + private static final long PAUSE_DURATION_MS = 60 * 1000; + + public WifiConnectionTest() { + super(WifiConnectionTest.class.getSimpleName()); + } @Override public void setUp() throws Exception { super.setUp(); - mNetworks = loadNetworkConfigurations(); - if (DEBUG) { - printNetworkConfigurations(); - } - - // enable wifi and verify wpa_supplicant is started - assertTrue("enable Wifi failed", enableWifi()); - assertTrue("wifi not connected", waitForNetworkState( - ConnectivityManager.TYPE_WIFI, State.CONNECTED, LONG_TIMEOUT)); - WifiInfo wi = mWifiManager.getConnectionInfo(); - assertNotNull("no active wifi info", wi); - assertTrue("failed to ping wpa_supplicant ", mWifiManager.pingSupplicant()); - } - - private void printNetworkConfigurations() { - log("==== print network configurations parsed from XML file ===="); - log("number of access points: " + mNetworks.size()); - for (WifiConfiguration config : mNetworks) { - log(config.toString()); - } + assertTrue("Failed to enable wifi", enableWifi()); } @Override @@ -72,25 +56,67 @@ public class WifiConnectionTest super.tearDown(); } - private void log(String message) { - Log.v(TAG, message); - } - @LargeTest public void testWifiConnections() { - for (int i = 0; i < mNetworks.size(); i++) { - String ssid = mNetworks.get(i).SSID; - log("-- START Wi-Fi connection test to : " + ssid + " --"); - connectToWifi(mNetworks.get(i)); + List<WifiConfiguration> wifiConfigs = loadConfigurations(); + + printWifiConfigurations(wifiConfigs); + + assertFalse("No configurations to test against", wifiConfigs.isEmpty()); + + boolean shouldPause = false; + for (WifiConfiguration config : wifiConfigs) { + if (shouldPause) { + logv("Pausing for %d seconds", PAUSE_DURATION_MS / 1000); + SystemClock.sleep(PAUSE_DURATION_MS); + } + logv("Start wifi connection test to: %s", config.SSID); + connectToWifi(config); + // verify that connection actually works - assertTrue("no network connectivity at end of test", checkNetworkConnectivity()); - log("-- END Wi-Fi connection test to " + ssid + " -- "); - log("pausing for 1 minute"); - try { - Thread.sleep(60 * 1000); - } catch (InterruptedException e) { - // ignore + assertTrue("No connectivity at end of test", checkNetworkConnectivity()); + + // Disconnect and remove the network + assertTrue("Unable to remove network", disconnectAP()); + logv("End wifi connection test to: %s", config.SSID); + + shouldPause = true; + } + } + + /** + * Load the configuration file from the root of the data partition + */ + private List<WifiConfiguration> loadConfigurations() { + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(new File(WIFI_CONFIG_FILE))); + StringBuffer jsonBuffer = new StringBuffer(); + String line; + while ((line = reader.readLine()) != null) { + jsonBuffer.append(line); + } + return WifiConfigurationHelper.parseJson(jsonBuffer.toString()); + } catch (IllegalArgumentException | IOException e) { + throw new AssertionError("Error parsing file", e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + // Ignore + } } } } + + /** + * Print the wifi configurations to test against. + */ + private void printWifiConfigurations(List<WifiConfiguration> wifiConfigs) { + logv("Wifi configurations to be tested"); + for (WifiConfiguration config : wifiConfigs) { + logv(config.toString()); + } + } } diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java index aead65b..41f01e6 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java @@ -17,16 +17,15 @@ package com.android.connectivitymanagertest.stress; -import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner; -import com.android.connectivitymanagertest.ConnectivityManagerTestBase; - import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiConfiguration.AuthAlgorithm; +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiManager; import android.os.Environment; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; + +import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner; +import com.android.connectivitymanagertest.ConnectivityManagerTestBase; import java.io.BufferedWriter; import java.io.File; @@ -35,9 +34,7 @@ import java.io.FileWriter; /** * Stress test setting up device as wifi hotspot */ -public class WifiApStress - extends ConnectivityManagerTestBase { - private final static String TAG = "WifiApStress"; +public class WifiApStress extends ConnectivityManagerTestBase { private static String NETWORK_ID = "AndroidAPTest"; private static String PASSWD = "androidwifi"; private final static String OUTPUT_FILE = "WifiStressTestOutput.txt"; @@ -46,6 +43,10 @@ public class WifiApStress private int mLastIteration = 0; private boolean mWifiOnlyFlag; + public WifiApStress() { + super(WifiApStress.class.getSimpleName()); + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -71,7 +72,7 @@ public class WifiApStress @LargeTest public void testWifiHotSpot() { if (mWifiOnlyFlag) { - Log.v(TAG, this.getName() + " is excluded for wi-fi only test"); + logv(getName() + " is excluded for wi-fi only test"); return; } WifiConfiguration config = new WifiConfiguration(); @@ -95,7 +96,7 @@ public class WifiApStress } int i; for (i = 0; i < mTotalIterations; i++) { - Log.v(TAG, "iteration: " + i); + logv("iteration: " + i); mLastIteration = i; // enable Wifi tethering assertTrue("failed to enable wifi hotspot", diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java index 6ef4f06..fbd4669 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java @@ -19,13 +19,10 @@ package com.android.connectivitymanagertest.stress; import android.app.Activity; import android.content.Context; import android.net.ConnectivityManager; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Environment; @@ -37,6 +34,7 @@ import android.util.Log; import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner; import com.android.connectivitymanagertest.ConnectivityManagerTestBase; +import com.android.connectivitymanagertest.WifiConfigurationHelper; import java.io.BufferedWriter; import java.io.File; @@ -52,8 +50,6 @@ import java.util.List; * -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner */ public class WifiStressTest extends ConnectivityManagerTestBase { - private final static String TAG = "WifiStressTest"; - private final static long SCREEN_OFF_TIMER = 500; //500ms /** * Wi-Fi idle time for default sleep policy @@ -78,6 +74,10 @@ public class WifiStressTest extends ConnectivityManagerTestBase { private BufferedWriter mOutputWriter = null; private boolean mWifiOnlyFlag; + public WifiStressTest() { + super(WifiStressTest.class.getSimpleName()); + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -89,14 +89,14 @@ public class WifiStressTest extends ConnectivityManagerTestBase { mScanIterations = mRunner.getScanIterations(); mWifiSleepTime = mRunner.getSleepTime(); mWifiOnlyFlag = mRunner.isWifiOnly(); - log(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s)," + logv(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s)," + "mScanIterations(%d), mWifiSleepTime(%d)", mReconnectIterations, mSsid, mPassword, mScanIterations, mWifiSleepTime)); mOutputWriter = new BufferedWriter(new FileWriter(new File( Environment.getExternalStorageDirectory(), OUTPUT_FILE), true)); turnScreenOn(); if (!mWifiManager.isWifiEnabled()) { - log("Enable wi-fi before stress tests."); + logv("Enable wi-fi before stress tests."); if (!enableWifi()) { tearDown(); fail("enable wifi failed."); @@ -107,7 +107,7 @@ public class WifiStressTest extends ConnectivityManagerTestBase { @Override protected void tearDown() throws Exception { - log("tearDown()"); + logv("tearDown()"); if (mOutputWriter != null) { mOutputWriter.close(); } @@ -115,23 +115,19 @@ public class WifiStressTest extends ConnectivityManagerTestBase { } private void writeOutput(String s) { - log("write message: " + s); + logv("write message: " + s); if (mOutputWriter == null) { - log("no writer attached to file " + OUTPUT_FILE); + logv("no writer attached to file " + OUTPUT_FILE); return; } try { mOutputWriter.write(s + "\n"); mOutputWriter.flush(); } catch (IOException e) { - log("failed to write output."); + logv("failed to write output."); } } - public void log(String message) { - Log.v(TAG, message); - } - private void sleep(long sometime, String errorMsg) { try { Thread.sleep(sometime); @@ -149,7 +145,7 @@ public class WifiStressTest extends ConnectivityManagerTestBase { long scanTimeSum = 0, i, averageScanTime = -1; int ssidAppearInScanResultsCount = 0; // count times of given ssid appear in scan results. for (i = 1; i <= mScanIterations; i++) { - log("testWifiScanning: iteration: " + i); + logv("testWifiScanning: iteration: " + i); averageScanTime = scanTimeSum / i; writeOutput(String.format("iteration %d out of %d", i, mScanIterations)); writeOutput(String.format("average scanning time is %d", averageScanTime)); @@ -173,9 +169,9 @@ public class WifiStressTest extends ConnectivityManagerTestBase { if (scanResultLocal == null || scanResultLocal.isEmpty()) { fail("Scan results are empty "); } - log("size of scan result list: " + scanResultLocal.size()); + logv("size of scan result list: " + scanResultLocal.size()); for (ScanResult sr : scanResultLocal) { - log(String.format("scan result: " + sr.toString())); + logv(String.format("scan result: " + sr.toString())); if (mSsid.equals(sr.SSID)) { ssidAppearInScanResultsCount += 1; break; @@ -208,21 +204,12 @@ public class WifiStressTest extends ConnectivityManagerTestBase { Settings.Global.putLong(mRunner.getContext().getContentResolver(), Settings.Global.WIFI_IDLE_MS, WIFI_IDLE_MS); - // Connect to a Wi-Fi network - WifiConfiguration config = new WifiConfiguration(); - config.SSID = mSsid; - if (mPassword != null) { - config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); - if (isHex(mPassword, 64)) { - config.preSharedKey = mPassword; - } else { - config.preSharedKey = '"' + mPassword + '"'; - } + WifiConfiguration config; + if (mPassword == null) { + config = WifiConfigurationHelper.createOpenConfig(mSsid); } else { - config.allowedKeyManagement.set(KeyMgmt.NONE); + config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword); } - config.setIpAssignment(IpAssignment.DHCP); - config.setProxySettings(ProxySettings.NONE); assertTrue("Failed to connect to Wi-Fi network: " + mSsid, connectToWifiWithConfiguration(config)); @@ -240,7 +227,7 @@ public class WifiStressTest extends ConnectivityManagerTestBase { // 5. Wake up the device, verify Wi-Fi is enabled and connected. writeOutput(String.format("iteration %d out of %d", i, mReconnectIterations)); - log("iteration: " + i); + logv("iteration: " + i); turnScreenOff(); // Use clock time since boot for intervals. long start = SystemClock.uptimeMillis(); @@ -271,7 +258,7 @@ public class WifiStressTest extends ConnectivityManagerTestBase { if (mWifiOnlyFlag) { NetworkInfo ni = mCm.getActiveNetworkInfo(); if (ni != null) { - Log.e(TAG, "has active network while in wifi sleep: " + ni.toString()); + Log.e(mLogTag, "has active network while in wifi sleep: " + ni.toString()); fail("active network detected"); } } else { @@ -292,7 +279,7 @@ public class WifiStressTest extends ConnectivityManagerTestBase { long connectionTime = SystemClock.uptimeMillis() - startTime; sum += connectionTime; avgReconnectTime = sum / i; - log("average reconnection time is: " + avgReconnectTime); + logv("average reconnection time is: " + avgReconnectTime); assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null)); } |