diff options
76 files changed, 1169 insertions, 450 deletions
@@ -485,6 +485,7 @@ package android { field public static final int focusable = 16842970; // 0x10100da field public static final int focusableInTouchMode = 16842971; // 0x10100db field public static final int focusedMonthDateColor = 16843587; // 0x1010343 + field public static final int fontFamily = 16843692; // 0x10103ac field public static final int footerDividersEnabled = 16843311; // 0x101022f field public static final int foreground = 16843017; // 0x1010109 field public static final int foregroundGravity = 16843264; // 0x1010200 @@ -5822,6 +5823,7 @@ package android.content { field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000 field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000 field public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 524288; // 0x80000 + field public static final int FLAG_ACTIVITY_CLOSE_SYSTEM_DIALOGS = 8192; // 0x2000 field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000 field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000 field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000 diff --git a/api/current.txt b/api/current.txt index 8402f31..1a694a8 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5823,6 +5823,7 @@ package android.content { field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000 field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000 field public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 524288; // 0x80000 + field public static final int FLAG_ACTIVITY_CLOSE_SYSTEM_DIALOGS = 8192; // 0x2000 field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000 field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000 field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000 diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index ac55abe..69ee434 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2713,7 +2713,16 @@ public class Activity extends ContextThemeWrapper onCreateNavigateUpTaskStack(b); onPrepareNavigateUpTaskStack(b); b.startActivities(); - finishAffinity(); + + // We can't finishAffinity if we have a result. + // Fall back and simply finish the current activity instead. + if (mResultCode != RESULT_CANCELED || mResultData != null) { + // Tell the developer what's going on to avoid hair-pulling. + Log.i(TAG, "onNavigateUp only finishing topmost activity to return a result"); + finish(); + } else { + finishAffinity(); + } } else { navigateUpTo(upIntent); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 5085b1e..b29035d 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2090,8 +2090,15 @@ public final class ActivityThread { r.activity.mCalled = false; mInstrumentation.callActivityOnPause(r.activity); // We need to keep around the original state, in case - // we need to be created again. - r.state = oldState; + // we need to be created again. But we only do this + // for pre-Honeycomb apps, which always save their state + // when pausing, so we can not have them save their state + // when restarting from a paused state. For HC and later, + // we want to (and can) let the state be saved as the normal + // part of stopping the activity. + if (r.isPreHoneycomb()) { + r.state = oldState; + } if (!r.activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index d3ba497..5e6b090 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -28,6 +28,7 @@ import android.os.Parcelable; import android.util.AndroidRuntimeException; import android.util.AttributeSet; import android.util.DebugUtils; +import android.util.Log; import android.util.SparseArray; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; @@ -108,7 +109,9 @@ final class FragmentState implements Parcelable { mInstance.mRetainInstance = mRetainInstance; mInstance.mDetached = mDetached; mInstance.mFragmentManager = activity.mFragments; - + if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG, + "Instantiated fragment " + mInstance); + return mInstance; } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 7e1daa4..6058bdc 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1074,6 +1074,7 @@ final class FragmentManagerImpl extends FragmentManager { f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1)); mActive.set(f.mIndex, f); } + if (DEBUG) Log.v(TAG, "Allocated fragment index " + f); } void makeInactive(Fragment f) { @@ -1081,7 +1082,7 @@ final class FragmentManagerImpl extends FragmentManager { return; } - if (DEBUG) Log.v(TAG, "Freeing fragment index " + f.mIndex); + if (DEBUG) Log.v(TAG, "Freeing fragment index " + f); mActive.set(f.mIndex, null); if (mAvailIndices == null) { mAvailIndices = new ArrayList<Integer>(); @@ -1493,6 +1494,7 @@ final class FragmentManagerImpl extends FragmentManager { fragments.add(f); f.mRetaining = true; f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1; + if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f); } } } diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 01b68d4..ed95ae5 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -38,6 +38,7 @@ import android.util.SparseArray; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Adapter; import android.widget.AdapterView; import android.widget.BaseAdapter; @@ -523,6 +524,12 @@ public class AppWidgetHostView extends FrameLayout { return tv; } + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(AppWidgetHostView.class.getName()); + } + private static class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable { public int describeContents() { return 0; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c791e47..718a917 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -808,13 +808,22 @@ public class Intent implements Parcelable, Cloneable { * always present to the user a list of the things they can do, with a * nice title given by the caller such as "Send this photo with:". * <p> + * If you need to grant URI permissions through a chooser, you must specify + * the permissions to be granted on the ACTION_CHOOSER Intent + * <em>in addition</em> to the EXTRA_INTENT inside. This means using + * {@link #setClipData} to specify the URIs to be granted as well as + * {@link #FLAG_GRANT_READ_URI_PERMISSION} and/or + * {@link #FLAG_GRANT_WRITE_URI_PERMISSION} as appropriate. + * <p> * As a convenience, an Intent of this form can be created with the * {@link #createChooser} function. - * <p>Input: No data should be specified. get*Extra must have + * <p> + * Input: No data should be specified. get*Extra must have * a {@link #EXTRA_INTENT} field containing the Intent being executed, * and can optionally have a {@link #EXTRA_TITLE} field containing the * title text to display in the chooser. - * <p>Output: Depends on the protocol of {@link #EXTRA_INTENT}. + * <p> + * Output: Depends on the protocol of {@link #EXTRA_INTENT}. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_CHOOSER = "android.intent.action.CHOOSER"; @@ -822,6 +831,14 @@ public class Intent implements Parcelable, Cloneable { /** * Convenience function for creating a {@link #ACTION_CHOOSER} Intent. * + * <p>Builds a new {@link #ACTION_CHOOSER} Intent that wraps the given + * target intent, also optionally supplying a title. If the target + * intent has specified {@link #FLAG_GRANT_READ_URI_PERMISSION} or + * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, then these flags will also be + * set in the returned chooser intent, with its ClipData set appropriately: + * either a direct reflection of {@link #getClipData()} if that is non-null, + * or a new ClipData build from {@link #getData()}. + * * @param target The Intent that the user will be selecting an activity * to perform. * @param title Optional title that will be displayed in the chooser. @@ -835,8 +852,31 @@ public class Intent implements Parcelable, Cloneable { if (title != null) { intent.putExtra(EXTRA_TITLE, title); } + + // Migrate any clip data and flags from target. + int permFlags = target.getFlags() + & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION); + if (permFlags != 0) { + ClipData targetClipData = target.getClipData(); + if (targetClipData == null && target.getData() != null) { + ClipData.Item item = new ClipData.Item(target.getData()); + String[] mimeTypes; + if (target.getType() != null) { + mimeTypes = new String[] { target.getType() }; + } else { + mimeTypes = new String[] { }; + } + targetClipData = new ClipData(null, mimeTypes, item); + } + if (targetClipData != null) { + intent.setClipData(targetClipData); + intent.addFlags(permFlags); + } + } + return intent; } + /** * Activity Action: Allow the user to select a particular kind of data and * return it. This is different than {@link #ACTION_PICK} in that here we @@ -3063,6 +3103,17 @@ public class Intent implements Parcelable, Cloneable { */ public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0X00004000; /** + * If set in an Intent passed to {@link Context#startActivity Context.startActivity()}, + * upon starting the activity the system will also clear any system dialogs that + * are currently shown. This is intended primarily for any actions that are + * associated with buttons in a notification: tapping on the button to launch + * the activity needs to also dismiss the notification window (which is one + * of the system dialogs); setting this flag on the Intent associated with that + * action will ensure that and other system dialogs are dismissed so that the + * user arrives in the new activity. + */ + public static final int FLAG_ACTIVITY_CLOSE_SYSTEM_DIALOGS = 0X00002000; + /** * If set, when sending a broadcast only registered receivers will be * called -- no BroadcastReceiver components will be launched. */ @@ -6587,19 +6638,35 @@ public class Intent implements Parcelable, Cloneable { /** * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and - * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. + * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested + * intents in {@link #ACTION_CHOOSER}. * + * @return Whether any contents were migrated. * @hide */ - public void migrateExtraStreamToClipData() { + public boolean migrateExtraStreamToClipData() { // Refuse to touch if extras already parcelled - if (mExtras != null && mExtras.isParcelled()) return; + if (mExtras != null && mExtras.isParcelled()) return false; // Bail when someone already gave us ClipData - if (getClipData() != null) return; + if (getClipData() != null) return false; final String action = getAction(); - if (ACTION_SEND.equals(action)) { + if (ACTION_CHOOSER.equals(action)) { + // Inspect target intent to see if we need to migrate + final Intent target = getParcelableExtra(EXTRA_INTENT); + if (target.migrateExtraStreamToClipData()) { + // Since we migrated in child, we need to promote ClipData and + // flags to ourselves to grant. + setClipData(target.getClipData()); + addFlags(target.getFlags() + & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION)); + return true; + } else { + return false; + } + + } else if (ACTION_SEND.equals(action)) { try { final Uri stream = getParcelableExtra(EXTRA_STREAM); final CharSequence text = getCharSequenceExtra(EXTRA_TEXT); @@ -6610,6 +6677,7 @@ public class Intent implements Parcelable, Cloneable { new ClipData.Item(text, htmlText, null, stream)); setClipData(clipData); addFlags(FLAG_GRANT_READ_URI_PERMISSION); + return true; } } catch (ClassCastException e) { } @@ -6626,14 +6694,14 @@ public class Intent implements Parcelable, Cloneable { if (texts != null) { if (num >= 0 && num != texts.size()) { // Wha...! F- you. - return; + return false; } num = texts.size(); } if (htmlTexts != null) { if (num >= 0 && num != htmlTexts.size()) { // Wha...! F- you. - return; + return false; } num = htmlTexts.size(); } @@ -6648,10 +6716,13 @@ public class Intent implements Parcelable, Cloneable { setClipData(clipData); addFlags(FLAG_GRANT_READ_URI_PERMISSION); + return true; } } catch (ClassCastException e) { } } + + return false; } private static ClipData.Item makeClipItem(ArrayList<Uri> streams, ArrayList<CharSequence> texts, diff --git a/core/java/android/preference/MultiSelectListPreference.java b/core/java/android/preference/MultiSelectListPreference.java index 2e8d551..553ce80 100644 --- a/core/java/android/preference/MultiSelectListPreference.java +++ b/core/java/android/preference/MultiSelectListPreference.java @@ -125,8 +125,9 @@ public class MultiSelectListPreference extends DialogPreference { * @param values The values to set for the key. */ public void setValues(Set<String> values) { - mValues = values; - + mValues.clear(); + mValues.addAll(values); + persistStringSet(values); } diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java index 09bf42b..1ef0916 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -105,6 +105,17 @@ public final class CalendarContract { * and it should call {@link Activity#setResult(int)} with * {@link Activity#RESULT_OK} or {@link Activity#RESULT_CANCELED} to * acknowledge whether the action was handled or not. + * + * The custom app should have an intent-filter like the following + * <pre> + * {@code + * <intent-filter> + * <action android:name="android.provider.calendar.action.HANDLE_CUSTOM_EVENT" /> + * <category android:name="android.intent.category.DEFAULT" /> + * <data android:mimeType="vnd.android.cursor.item/event" /> + * </intent-filter> + * } + * </pre> * <p> * Input: {@link Intent#getData} has the event URI. The extra * {@link #EXTRA_EVENT_BEGIN_TIME} has the start time of the instance. The diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index e1f1db2..6dc31dd 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -29,7 +29,6 @@ import android.util.Poolable; import android.util.PoolableManager; import android.util.Pools; import android.util.SparseLongArray; -import android.view.ViewGroup.ChildListForAccessibility; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeProvider; @@ -491,20 +490,28 @@ final class AccessibilityInteractionController { if ((direction & View.FOCUS_ACCESSIBILITY) == View.FOCUS_ACCESSIBILITY) { AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider(); if (provider != null) { - next = provider.accessibilityFocusSearch(direction, - virtualDescendantId); - } else if (virtualDescendantId == View.NO_ID) { - View nextView = root.focusSearch(direction); - if (nextView != null) { - // If the focus search reached a node with a provider - // we delegate to the provider to find the next one. - provider = nextView.getAccessibilityNodeProvider(); - if (provider != null) { - next = provider.accessibilityFocusSearch(direction, - virtualDescendantId); - } else { - next = nextView.createAccessibilityNodeInfo(); - } + next = provider.accessibilityFocusSearch(direction, virtualDescendantId); + if (next != null) { + return; + } + } + View nextView = root.focusSearch(direction); + while (nextView != null) { + // If the focus search reached a node with a provider + // we delegate to the provider to find the next one. + // If the provider does not return a virtual view to + // take accessibility focus we try the next view found + // by the focus search algorithm. + provider = nextView.getAccessibilityNodeProvider(); + if (provider != null) { + next = provider.accessibilityFocusSearch(direction, View.NO_ID); + if (next != null) { + break; + } + nextView = nextView.focusSearch(direction); + } else { + next = nextView.createAccessibilityNodeInfo(); + break; } } } else { @@ -615,6 +622,8 @@ final class AccessibilityInteractionController { private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 50; + private final ArrayList<View> mTempViewList = new ArrayList<View>(); + public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int prefetchFlags, List<AccessibilityNodeInfo> outInfos) { AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider(); @@ -655,8 +664,6 @@ final class AccessibilityInteractionController { while (parent instanceof View && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { View parentView = (View) parent; - final long parentNodeId = AccessibilityNodeInfo.makeNodeId( - parentView.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED); AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo(); if (info != null) { outInfos.add(info); @@ -670,19 +677,21 @@ final class AccessibilityInteractionController { ViewParent parent = current.getParentForAccessibility(); if (parent instanceof ViewGroup) { ViewGroup parentGroup = (ViewGroup) parent; - ChildListForAccessibility children = ChildListForAccessibility.obtain(parentGroup, - false); + ArrayList<View> children = mTempViewList; + children.clear(); try { - final int childCount = children.getChildCount(); + parentGroup.addChildrenForAccessibility(children); + final int childCount = children.size(); for (int i = 0; i < childCount; i++) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } - View child = children.getChildAt(i); + View child = children.get(i); if (child.getAccessibilityViewId() != current.getAccessibilityViewId() && isShown(child)) { AccessibilityNodeInfo info = null; - AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider(); + AccessibilityNodeProvider provider = + child.getAccessibilityNodeProvider(); if (provider == null) { info = child.createAccessibilityNodeInfo(); } else { @@ -695,7 +704,7 @@ final class AccessibilityInteractionController { } } } finally { - children.recycle(); + children.clear(); } } } @@ -708,14 +717,16 @@ final class AccessibilityInteractionController { ViewGroup rootGroup = (ViewGroup) root; HashMap<View, AccessibilityNodeInfo> addedChildren = new HashMap<View, AccessibilityNodeInfo>(); - ChildListForAccessibility children = ChildListForAccessibility.obtain(rootGroup, false); + ArrayList<View> children = mTempViewList; + children.clear(); try { - final int childCount = children.getChildCount(); + root.addChildrenForAccessibility(children); + final int childCount = children.size(); for (int i = 0; i < childCount; i++) { if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { return; } - View child = children.getChildAt(i); + View child = children.get(i); if (isShown(child)) { AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider(); if (provider == null) { @@ -735,7 +746,7 @@ final class AccessibilityInteractionController { } } } finally { - children.recycle(); + children.clear(); } if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 14523d3..a4fcd41 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6027,7 +6027,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal return; } if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) { - if (canTakeAccessibilityFocusFromHover()) { + if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) { views.add(this); return; } @@ -6156,12 +6156,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * @hide */ public void clearAccessibilityFocus() { - if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) { - mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED; - ViewRootImpl viewRootImpl = getViewRootImpl(); - if (viewRootImpl != null) { + ViewRootImpl viewRootImpl = getViewRootImpl(); + if (viewRootImpl != null) { + View focusHost = viewRootImpl.getAccessibilityFocusedHost(); + if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { viewRootImpl.setAccessibilityFocusedHost(null); } + } + if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) { + mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED; invalidate(); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); notifyAccessibilityStateChanged(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f86e036..bcd336d 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -488,7 +488,9 @@ public final class ViewRootImpl implements ViewParent, mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); attrs = mWindowAttributes; - + + setAccessibilityFocusedHost(null); + if (view instanceof RootViewSurfaceTaker) { mSurfaceHolderCallback = ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); @@ -556,6 +558,7 @@ public final class ViewRootImpl implements ViewParent, mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); + setAccessibilityFocusedHost(null); throw new RuntimeException("Adding window failed", e); } finally { if (restore) { @@ -575,6 +578,7 @@ public final class ViewRootImpl implements ViewParent, mAdded = false; mFallbackEventHandler.setView(null); unscheduleTraversals(); + setAccessibilityFocusedHost(null); switch (res) { case WindowManagerImpl.ADD_BAD_APP_TOKEN: case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN: @@ -635,8 +639,6 @@ public final class ViewRootImpl implements ViewParent, if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } - - setAccessibilityFocusedHost(null); } } } @@ -1853,18 +1855,15 @@ public final class ViewRootImpl implements ViewParent, performDraw(); } } else { - // End any pending transitions on this non-visible window - if (mPendingTransitions != null && mPendingTransitions.size() > 0) { + if (viewVisibility == View.VISIBLE) { + // Try again + scheduleTraversals(); + } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) { for (int i = 0; i < mPendingTransitions.size(); ++i) { mPendingTransitions.get(i).endChangingAnimations(); } mPendingTransitions.clear(); } - - if (viewVisibility == View.VISIBLE) { - // Try again - scheduleTraversals(); - } } } @@ -2184,6 +2183,18 @@ public final class ViewRootImpl implements ViewParent, private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff, boolean scalingRequired, Rect dirty) { + // If we get here with a disabled & requested hardware renderer, something went + // wrong (an invalidate posted right before we destroyed the hardware surface + // for instance) so we should just bail out. Locking the surface with software + // rendering at this point would lock it forever and prevent hardware renderer + // from doing its job when it comes back. + if (attachInfo.mHardwareRenderer != null && !attachInfo.mHardwareRenderer.isEnabled() && + attachInfo.mHardwareRenderer.isRequested()) { + mFullRedrawNeeded = true; + scheduleTraversals(); + return false; + } + // Draw with software renderer. Canvas canvas; try { @@ -2543,11 +2554,51 @@ public final class ViewRootImpl implements ViewParent, } void setAccessibilityFocusedHost(View host) { - if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView == null) { + // If we have a virtual view with accessibility focus we need + // to clear the focus and invalidate the virtual view bounds. + if (mAccessibilityFocusedVirtualView != null) { + + AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView; + View focusHost = mAccessibilityFocusedHost; + focusHost.clearAccessibilityFocusNoCallbacks(); + + // Wipe the state of the current accessibility focus since + // the call into the provider to clear accessibility focus + // will fire an accessibility event which will end up calling + // this method and we want to have clean state when this + // invocation happens. + mAccessibilityFocusedHost = null; + mAccessibilityFocusedVirtualView = null; + + AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider(); + if (provider != null) { + // Invalidate the area of the cleared accessibility focus. + focusNode.getBoundsInParent(mTempRect); + focusHost.invalidate(mTempRect); + // Clear accessibility focus in the virtual node. + final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( + focusNode.getSourceNodeId()); + provider.performAction(virtualNodeId, + AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); + } + } + if (mAccessibilityFocusedHost != null) { + // Clear accessibility focus in the view. mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(); } + + // Set the new focus host. mAccessibilityFocusedHost = host; - mAccessibilityFocusedVirtualView = null; + + // If the host has a provide find the virtual descendant that has focus. + if (mAccessibilityFocusedHost != null) { + AccessibilityNodeProvider provider = + mAccessibilityFocusedHost.getAccessibilityNodeProvider(); + if (provider != null) { + mAccessibilityFocusedVirtualView = provider.findAccessibilityFocus(View.NO_ID); + return; + } + } } public void requestChildFocus(View child, View focused) { @@ -2633,6 +2684,8 @@ public final class ViewRootImpl implements ViewParent, destroyHardwareRenderer(); + setAccessibilityFocusedHost(null); + mView = null; mAttachInfo.mRootView = null; mAttachInfo.mSurface = null; @@ -4608,6 +4661,31 @@ public final class ViewRootImpl implements ViewParent, if (mView == null) { return false; } + // Watch for accessibility focus change events from virtual nodes + // to keep track of accessibility focus being on a virtual node. + final int eventType = event.getEventType(); + switch (eventType) { + case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { + final long sourceId = event.getSourceNodeId(); + // If the event is not from a virtual node we are not interested. + final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(sourceId); + if (virtualViewId == AccessibilityNodeInfo.UNDEFINED) { + break; + } + final int realViewId = AccessibilityNodeInfo.getAccessibilityViewId(sourceId); + View focusHost = mView.findViewByAccessibilityId(realViewId); + setAccessibilityFocusedHost(focusHost); + } break; + case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { + final long sourceId = event.getSourceNodeId(); + // If the event is not from a virtual node we are not interested. + final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(sourceId); + if (virtualViewId == AccessibilityNodeInfo.UNDEFINED) { + break; + } + setAccessibilityFocusedHost(null); + } break; + } mAccessibilityManager.sendAccessibilityEvent(event); return true; } diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index bd341d0..20b5f17 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -19,6 +19,7 @@ package android.view.accessibility; import android.accessibilityservice.IAccessibilityServiceConnection; import android.graphics.Rect; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Message; import android.os.Process; @@ -27,10 +28,14 @@ import android.os.SystemClock; import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; +import android.util.SparseLongArray; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; +import java.util.Queue; import java.util.concurrent.atomic.AtomicInteger; /** @@ -74,6 +79,8 @@ public final class AccessibilityInteractionClient private static final boolean DEBUG = false; + private static final boolean CHECK_INTEGRITY = true; + private static final long TIMEOUT_INTERACTION_MILLIS = 5000; private static final Object sStaticLock = new Object(); @@ -491,6 +498,9 @@ public final class AccessibilityInteractionClient result = Collections.emptyList(); } clearResultLocked(); + if (Build.IS_DEBUGGABLE && CHECK_INTEGRITY) { + checkFindAccessibilityNodeInfoResultIntegrity(result); + } return result; } } @@ -696,4 +706,56 @@ public final class AccessibilityInteractionClient sConnectionCache.remove(connectionId); } } + + /** + * Checks whether the infos are a fully connected tree with no duplicates. + * + * @param infos The result list to check. + */ + private void checkFindAccessibilityNodeInfoResultIntegrity(List<AccessibilityNodeInfo> infos) { + if (infos.size() == 0) { + return; + } + // Find the root node. + AccessibilityNodeInfo root = infos.get(0); + final int infoCount = infos.size(); + for (int i = 1; i < infoCount; i++) { + for (int j = i; j < infoCount; j++) { + AccessibilityNodeInfo candidate = infos.get(j); + if (root.getParentNodeId() == candidate.getSourceNodeId()) { + root = candidate; + break; + } + } + } + if (root == null) { + Log.e(LOG_TAG, "No root."); + } + // Check for duplicates. + HashSet<AccessibilityNodeInfo> seen = new HashSet<AccessibilityNodeInfo>(); + Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>(); + fringe.add(root); + while (!fringe.isEmpty()) { + AccessibilityNodeInfo current = fringe.poll(); + if (!seen.add(current)) { + Log.e(LOG_TAG, "Duplicate node."); + return; + } + SparseLongArray childIds = current.getChildNodeIds(); + final int childCount = childIds.size(); + for (int i = 0; i < childCount; i++) { + final long childId = childIds.valueAt(i); + for (int j = 0; j < infoCount; j++) { + AccessibilityNodeInfo child = infos.get(j); + if (child.getSourceNodeId() == childId) { + fringe.add(child); + } + } + } + } + final int disconnectedCount = infos.size() - seen.size(); + if (disconnectedCount > 0) { + Log.e(LOG_TAG, disconnectedCount + " Disconnected nodes."); + } + } } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java index 52b7772..14954be 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java @@ -244,7 +244,7 @@ public class AccessibilityNodeInfoCache { /** * We are enforcing the invariant for a single accessibility focus. * - * @param currentInputFocusId The current input focused node. + * @param currentAccessibilityFocusId The current input focused node. */ private void clearSubtreeWithOldAccessibilityFocusLocked(long currentAccessibilityFocusId) { final int cacheSize = mCacheImpl.size(); diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index f4796d5..f1f3db2 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -1716,6 +1716,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc mZoomManager.updateDefaultZoomDensity(density); } + /* package */ int getScaledNavSlop() { + return viewToContentDimension(mNavSlop); + } + /* package */ boolean onSavePassword(String schemePlusHost, String username, String password, final Message resumeMsg) { boolean rVal = false; @@ -2939,6 +2943,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc // premature data from webkit, ignore if ((w | h) == 0) { + invalidate(); return; } @@ -2951,10 +2956,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc // updated when we get out of that mode. if (!mDrawHistory) { // repin our scroll, taking into account the new content size - if (updateScrollCoordinates(pinLocX(getScrollX()), - pinLocY(getScrollY()))) { - invalidate(); - } + updateScrollCoordinates(pinLocX(getScrollX()), pinLocY(getScrollY())); if (!mScroller.isFinished()) { // We are in the middle of a scroll. Repin the final scroll // position. @@ -2962,6 +2964,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc mScroller.setFinalY(pinLocY(mScroller.getFinalY())); } } + invalidate(); } contentSizeChanged(updateLayout); } @@ -4339,10 +4342,6 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } private void removeTouchHighlight() { - if (mWebViewCore != null) { - mWebViewCore.removeMessages(EventHub.HIT_TEST); - } - mPrivateHandler.removeMessages(HIT_TEST_RESULT); setTouchHighlightRects(null); } @@ -5817,7 +5816,6 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc switch (action) { case MotionEvent.ACTION_DOWN: { mConfirmMove = false; - mInitialHitTestResult = null; if (!mEditTextScroller.isFinished()) { mEditTextScroller.abortAnimation(); } @@ -5839,23 +5837,6 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } } else { // the normal case mTouchMode = TOUCH_INIT_MODE; - // TODO: Have WebViewInputDispatch handle this - TouchHighlightData data = new TouchHighlightData(); - data.mX = contentX; - data.mY = contentY; - data.mNativeLayerRect = new Rect(); - if (mNativeClass != 0) { - data.mNativeLayer = nativeScrollableLayer(mNativeClass, - contentX, contentY, data.mNativeLayerRect, null); - } else { - data.mNativeLayer = 0; - } - data.mSlop = viewToContentDimension(mNavSlop); - removeTouchHighlight(); - if (!mBlockWebkitViewMessages && mWebViewCore != null) { - mWebViewCore.sendMessageAtFrontOfQueue( - EventHub.HIT_TEST, data); - } if (mLogEvent && eventTime - mLastTouchUpTime < 1000) { EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION, (eventTime - mLastTouchUpTime), eventTime); @@ -7956,7 +7937,8 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } // update the zoom information based on the new picture - mZoomManager.onNewPicture(draw); + if (mZoomManager.onNewPicture(draw)) + invalidate(); if (isPictureAfterFirstLayout) { mViewManager.postReadyToDrawAll(); @@ -7986,7 +7968,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } nativeSetTextSelection(mNativeClass, data.mSelectTextPtr); - if (data.mSelectionReason == TextSelectionData.REASON_ACCESSIBILITY_INJECTOR) { + if ((data.mSelectionReason == TextSelectionData.REASON_ACCESSIBILITY_INJECTOR) + || (!mSelectingText + && data.mSelectionReason != TextSelectionData.REASON_SELECT_WORD)) { selectionDone(); mShowTextSelectionExtra = true; invalidate(); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 4adfd6a..76cd1c9 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -22,7 +22,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.Region; import android.media.MediaFile; import android.net.ProxyProperties; import android.net.Uri; @@ -864,6 +863,7 @@ public final class WebViewCore { static class TextSelectionData { static final int REASON_UNKNOWN = 0; static final int REASON_ACCESSIBILITY_INJECTOR = 1; + static final int REASON_SELECT_WORD = 2; public TextSelectionData(int start, int end, int selectTextPtr) { mStart = start; mEnd = end; @@ -1143,8 +1143,6 @@ public final class WebViewCore { static final int ADD_PACKAGE_NAME = 185; static final int REMOVE_PACKAGE_NAME = 186; - static final int HIT_TEST = 187; - // accessibility support static final int MODIFY_SELECTION = 190; @@ -1648,18 +1646,6 @@ public final class WebViewCore { (Set<String>) msg.obj); break; - case HIT_TEST: - TouchHighlightData d = (TouchHighlightData) msg.obj; - if (d.mNativeLayer != 0) { - nativeScrollLayer(mNativeClass, - d.mNativeLayer, d.mNativeLayerRect); - } - WebKitHitTest hit = performHitTest(d.mX, d.mY, d.mSlop, true); - mWebViewClassic.mPrivateHandler.obtainMessage( - WebViewClassic.HIT_TEST_RESULT, hit) - .sendToTarget(); - break; - case SET_USE_MOCK_DEVICE_ORIENTATION: setUseMockDeviceOrientation(); break; @@ -1718,12 +1704,16 @@ public final class WebViewCore { break; } case SELECT_WORD_AT: { + mTextSelectionChangeReason + = TextSelectionData.REASON_SELECT_WORD; int x = msg.arg1; int y = msg.arg2; if (!nativeSelectWordAt(mNativeClass, x, y)) { mWebViewClassic.mPrivateHandler.obtainMessage(WebViewClassic.SHOW_CARET_HANDLE) .sendToTarget(); } + mTextSelectionChangeReason + = TextSelectionData.REASON_UNKNOWN; break; } case SELECT_ALL: @@ -1788,6 +1778,15 @@ public final class WebViewCore { return false; } switch (eventType) { + case WebViewInputDispatcher.EVENT_TYPE_HIT_TEST: + int x = Math.round(event.getX()); + int y = Math.round(event.getY()); + WebKitHitTest hit = performHitTest(x, y, + mWebViewClassic.getScaledNavSlop(), true); + mWebViewClassic.mPrivateHandler.obtainMessage( + WebViewClassic.HIT_TEST_RESULT, hit).sendToTarget(); + return false; + case WebViewInputDispatcher.EVENT_TYPE_CLICK: return nativeMouseClick(mNativeClass); diff --git a/core/java/android/webkit/WebViewInputDispatcher.java b/core/java/android/webkit/WebViewInputDispatcher.java index 9328d8c..9eeb311 100644 --- a/core/java/android/webkit/WebViewInputDispatcher.java +++ b/core/java/android/webkit/WebViewInputDispatcher.java @@ -204,6 +204,11 @@ final class WebViewInputDispatcher { public static final int EVENT_TYPE_DOUBLE_TAP = 5; /** + * Event type: Indicates that a hit test should be performed + */ + public static final int EVENT_TYPE_HIT_TEST = 6; + + /** * Flag: This event is private to this queue. Do not forward it. */ public static final int FLAG_PRIVATE = 1 << 0; @@ -499,13 +504,17 @@ final class WebViewInputDispatcher { } private void enqueueDoubleTapLocked(MotionEvent event) { - unscheduleClickLocked(); - hideTapCandidateLocked(); MotionEvent eventToEnqueue = MotionEvent.obtainNoHistory(event); DispatchEvent d = obtainDispatchEventLocked(eventToEnqueue, EVENT_TYPE_DOUBLE_TAP, 0, mPostLastWebKitXOffset, mPostLastWebKitYOffset, mPostLastWebKitScale); enqueueEventLocked(d); - mIsDoubleTapCandidate = false; + } + + private void enqueueHitTestLocked(MotionEvent event) { + MotionEvent eventToEnqueue = MotionEvent.obtainNoHistory(event); + DispatchEvent d = obtainDispatchEventLocked(eventToEnqueue, EVENT_TYPE_HIT_TEST, 0, + mPostLastWebKitXOffset, mPostLastWebKitYOffset, mPostLastWebKitScale); + enqueueEventLocked(d); } private void checkForSlopLocked(MotionEvent event) { @@ -545,6 +554,7 @@ final class WebViewInputDispatcher { mInitialDownX = event.getX(); mInitialDownY = event.getY(); scheduleShowTapHighlightLocked(); + enqueueHitTestLocked(event); } else if (action == MotionEvent.ACTION_UP) { unscheduleLongPressLocked(); if (isClickCandidateLocked(event)) { @@ -824,6 +834,7 @@ final class WebViewInputDispatcher { case EVENT_TYPE_CLICK: case EVENT_TYPE_HOVER: case EVENT_TYPE_SCROLL: + case EVENT_TYPE_HIT_TEST: return false; case EVENT_TYPE_TOUCH: return !mPostSendTouchEventsToWebKit diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 2247678..1da59e4 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -1008,8 +1008,10 @@ class ZoomManager { /** * Updates zoom values when Webkit produces a new picture. This method * should only be called from the UI thread's message handler. + * + * @return True if zoom value has changed */ - public void onNewPicture(WebViewCore.DrawData drawData) { + public boolean onNewPicture(WebViewCore.DrawData drawData) { final int viewWidth = mWebView.getViewWidth(); final boolean zoomOverviewWidthChanged = setupZoomOverviewWidth(drawData, viewWidth); final float newZoomOverviewScale = getZoomOverviewScale(); @@ -1056,6 +1058,8 @@ class ZoomManager { // so next new picture could be forced into overview mode if it's true. mInitialZoomOverview = mInZoomOverview; } + + return scaleHasDiff; } /** diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index ab9d370..04c8cdc 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -1480,6 +1480,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @Override public boolean performAccessibilityAction(int action, Bundle arguments) { + if (super.performAccessibilityAction(action, arguments)) { + return true; + } switch (action) { case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { if (getLastVisiblePosition() < getCount() - 1) { @@ -1496,7 +1499,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } return false; } - return super.performAccessibilityAction(action, arguments); + return false; } /** diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java index c6104bc..fe6c4f5 100644 --- a/core/java/android/widget/ActivityChooserModel.java +++ b/core/java/android/widget/ActivityChooserModel.java @@ -765,16 +765,6 @@ public class ActivityChooserModel extends DataSetObservable { } /** - * Gets whether the given observer is already registered. - * - * @param observer The observer. - * @return True if already registered. - */ - public boolean isRegisteredObserver(DataSetObserver observer) { - return mObservers.contains(observer); - } - - /** * Represents a record in the history. */ public final static class HistoricalRecord { diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java index 0c0bb1e..be6b4e2 100644 --- a/core/java/android/widget/ActivityChooserView.java +++ b/core/java/android/widget/ActivityChooserView.java @@ -20,10 +20,8 @@ import com.android.internal.R; import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.database.DataSetObserver; @@ -176,11 +174,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod private int mDefaultActionButtonContentDescription; /** - * Whether this view has a default activity affordance. - */ - private boolean mHasDefaultActivity; - - /** * Create a new instance. * * @param context The application environment. @@ -252,8 +245,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod Resources resources = context.getResources(); mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2, resources.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth)); - - updateHasDefaultActivity(); } /** @@ -267,21 +258,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod } } - @Override - protected void onConfigurationChanged(Configuration newConfig) { - Configuration oldConfig = mContext.getResources().getConfiguration(); - final int changed = oldConfig.diff(newConfig); - if ((changed & ActivityInfo.CONFIG_SCREEN_SIZE) != 0 - || (changed & ActivityInfo.CONFIG_ORIENTATION) != 0) { - updateHasDefaultActivity(); - } - } - - private void updateHasDefaultActivity() { - mHasDefaultActivity = mContext.getResources().getBoolean( - R.bool.activity_chooser_view_has_default_activity); - } - /** * Sets the background for the button that expands the activity * overflow list. @@ -407,8 +383,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod protected void onAttachedToWindow() { super.onAttachedToWindow(); ActivityChooserModel dataModel = mAdapter.getDataModel(); - if (dataModel != null - && !dataModel.isRegisteredObserver(mModelDataSetOberver)) { + if (dataModel != null) { dataModel.registerObserver(mModelDataSetOberver); } mIsAttachedToWindow = true; @@ -418,8 +393,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod protected void onDetachedFromWindow() { super.onDetachedFromWindow(); ActivityChooserModel dataModel = mAdapter.getDataModel(); - if (dataModel != null - && dataModel.isRegisteredObserver(mModelDataSetOberver)) { + if (dataModel != null) { dataModel.unregisterObserver(mModelDataSetOberver); } ViewTreeObserver viewTreeObserver = getViewTreeObserver(); @@ -522,7 +496,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod // Default activity button. final int activityCount = mAdapter.getActivityCount(); final int historySize = mAdapter.getHistorySize(); - if (mHasDefaultActivity && activityCount > 0 && historySize > 0) { + if (activityCount > 0 && historySize > 0) { mDefaultActivityButton.setVisibility(VISIBLE); ResolveInfo activity = mAdapter.getDefaultActivity(); PackageManager packageManager = mContext.getPackageManager(); @@ -538,9 +512,9 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod } // Activity chooser content. if (mDefaultActivityButton.getVisibility() == VISIBLE) { - mActivityChooserContent.setBackground(mActivityChooserContentBackground); + mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground); } else { - mActivityChooserContent.setBackground(null); + mActivityChooserContent.setBackgroundDrawable(null); } } @@ -603,7 +577,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod // OnLongClickListener#onLongClick @Override public boolean onLongClick(View view) { - if (mHasDefaultActivity && view == mDefaultActivityButton) { + if (view == mDefaultActivityButton) { if (mAdapter.getCount() > 0) { mIsSelectingDefaultActivity = true; showPopupUnchecked(mInitialActivityCount); @@ -656,16 +630,14 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod public void setDataModel(ActivityChooserModel dataModel) { ActivityChooserModel oldDataModel = mAdapter.getDataModel(); - if (oldDataModel != null) { + if (oldDataModel != null && isShown()) { oldDataModel.unregisterObserver(mModelDataSetOberver); } mDataModel = dataModel; - if (dataModel != null) { + if (dataModel != null && isShown()) { dataModel.registerObserver(mModelDataSetOberver); - notifyDataSetChanged(); - } else { - notifyDataSetInvalidated(); } + notifyDataSetChanged(); } @Override diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index 03fdc39..b2c8164 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -20,6 +20,7 @@ import android.annotation.Widget; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; +import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.ContextMenu.ContextMenuInfo; @@ -1367,6 +1368,35 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(Gallery.class.getName()); + info.setScrollable(mItemCount > 1); + if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + if (mItemCount > 0 && mSelectedPosition > 0) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + } + + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + if (super.performAccessibilityAction(action, arguments)) { + return true; + } + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) { + final int currentChildIndex = mSelectedPosition - mFirstPosition; + return scrollToChild(currentChildIndex + 1); + } + } return false; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + if (mItemCount > 0 && mSelectedPosition > 0) { + final int currentChildIndex = mSelectedPosition - mFirstPosition; + return scrollToChild(currentChildIndex - 1); + } + } return false; + } + return false; } /** diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index ffabd1d..f889cb7 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -739,6 +739,9 @@ public class HorizontalScrollView extends FrameLayout { @Override public boolean performAccessibilityAction(int action, Bundle arguments) { + if (super.performAccessibilityAction(action, arguments)) { + return true; + } switch (action) { case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight; @@ -757,7 +760,7 @@ public class HorizontalScrollView extends FrameLayout { } } return false; } - return super.performAccessibilityAction(action, arguments); + return false; } @Override diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 7c809b3..515f0c4 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -950,6 +950,8 @@ public class NumberPicker extends LinearLayout { provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); mLastHoveredChildVirtualViewId = hoveredVirtualViewId; + provider.performAction(hoveredVirtualViewId, + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); } break; case MotionEvent.ACTION_HOVER_MOVE: { if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId @@ -960,6 +962,8 @@ public class NumberPicker extends LinearLayout { provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); mLastHoveredChildVirtualViewId = hoveredVirtualViewId; + provider.performAction(hoveredVirtualViewId, + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); } } break; case MotionEvent.ACTION_HOVER_EXIT: { @@ -1413,9 +1417,16 @@ public class NumberPicker extends LinearLayout { } @Override - public void sendAccessibilityEvent(int eventType) { - // Do not send accessibility events - we want the user to - // perceive this widget as several controls rather as a whole. + public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { + // We do not want the real descendant to be considered focus search + // since it is managed by the accessibility node provider. + if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) { + if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) { + views.add(this); + return; + } + } + super.addFocusables(views, direction, focusableMode); } @Override @@ -2072,7 +2083,12 @@ public class NumberPicker extends LinearLayout { } } + /** + * Class for managing virtual view tree rooted at this picker. + */ class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider { + private static final int UNDEFINED = Integer.MIN_VALUE; + private static final int VIRTUAL_VIEW_ID_INCREMENT = 1; private static final int VIRTUAL_VIEW_ID_INPUT = 2; @@ -2083,6 +2099,8 @@ public class NumberPicker extends LinearLayout { private final int[] mTempArray = new int[2]; + private int mAccessibilityFocusedView = UNDEFINED; + @Override public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { switch (virtualViewId) { @@ -2137,6 +2155,37 @@ public class NumberPicker extends LinearLayout { @Override public boolean performAction(int virtualViewId, int action, Bundle arguments) { switch (virtualViewId) { + case View.NO_ID: { + switch (action) { + case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { + if (mAccessibilityFocusedView != virtualViewId) { + mAccessibilityFocusedView = virtualViewId; + requestAccessibilityFocus(); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { + if (mAccessibilityFocusedView == virtualViewId) { + mAccessibilityFocusedView = UNDEFINED; + clearAccessibilityFocus(); + return true; + } + return false; + } + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + if (getWrapSelectorWheel() || getValue() < getMaxValue()) { + changeValueByOne(true); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + if (getWrapSelectorWheel() || getValue() > getMinValue()) { + changeValueByOne(false); + return true; + } + } return false; + } + } break; case VIRTUAL_VIEW_ID_INPUT: { switch (action) { case AccessibilityNodeInfo.ACTION_FOCUS: { @@ -2149,25 +2198,182 @@ public class NumberPicker extends LinearLayout { mInputText.clearFocus(); return true; } - } break; + return false; + } + case AccessibilityNodeInfo.ACTION_CLICK: { + showSoftInput(); + return true; + } + case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { + if (mAccessibilityFocusedView != virtualViewId) { + mAccessibilityFocusedView = virtualViewId; + sendAccessibilityEventForVirtualView(virtualViewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); + mInputText.invalidate(); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { + if (mAccessibilityFocusedView == virtualViewId) { + mAccessibilityFocusedView = UNDEFINED; + sendAccessibilityEventForVirtualView(virtualViewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); + mInputText.invalidate(); + return true; + } + } return false; + default: { + return mInputText.performAccessibilityAction(action, arguments); + } } - } break; + } return false; + case VIRTUAL_VIEW_ID_INCREMENT: { + switch (action) { + case AccessibilityNodeInfo.ACTION_CLICK: { + NumberPicker.this.changeValueByOne(true); + sendAccessibilityEventForVirtualView(virtualViewId, + AccessibilityEvent.TYPE_VIEW_CLICKED); + } return true; + case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { + if (mAccessibilityFocusedView != virtualViewId) { + mAccessibilityFocusedView = virtualViewId; + sendAccessibilityEventForVirtualView(virtualViewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); + invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { + if (mAccessibilityFocusedView == virtualViewId) { + mAccessibilityFocusedView = UNDEFINED; + sendAccessibilityEventForVirtualView(virtualViewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); + invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); + return true; + } + } return false; + } + } return false; + case VIRTUAL_VIEW_ID_DECREMENT: { + switch (action) { + case AccessibilityNodeInfo.ACTION_CLICK: { + final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT); + NumberPicker.this.changeValueByOne(increment); + sendAccessibilityEventForVirtualView(virtualViewId, + AccessibilityEvent.TYPE_VIEW_CLICKED); + } return true; + case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { + if (mAccessibilityFocusedView != virtualViewId) { + mAccessibilityFocusedView = virtualViewId; + sendAccessibilityEventForVirtualView(virtualViewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); + invalidate(0, 0, mRight, mTopSelectionDividerTop); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { + if (mAccessibilityFocusedView == virtualViewId) { + mAccessibilityFocusedView = UNDEFINED; + sendAccessibilityEventForVirtualView(virtualViewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); + invalidate(0, 0, mRight, mTopSelectionDividerTop); + return true; + } + } return false; + } + } return false; } return super.performAction(virtualViewId, action, arguments); } + @Override + public AccessibilityNodeInfo findAccessibilityFocus(int virtualViewId) { + return createAccessibilityNodeInfo(mAccessibilityFocusedView); + } + + @Override + public AccessibilityNodeInfo accessibilityFocusSearch(int direction, int virtualViewId) { + switch (direction) { + case View.ACCESSIBILITY_FOCUS_DOWN: + case View.ACCESSIBILITY_FOCUS_FORWARD: { + switch (mAccessibilityFocusedView) { + case UNDEFINED: { + return createAccessibilityNodeInfo(View.NO_ID); + } + case View.NO_ID: { + if (hasVirtualDecrementButton()) { + return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT); + } + } + //$FALL-THROUGH$ + case VIRTUAL_VIEW_ID_DECREMENT: { + return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT); + } + case VIRTUAL_VIEW_ID_INPUT: { + if (hasVirtualIncrementButton()) { + return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT); + } + } + //$FALL-THROUGH$ + case VIRTUAL_VIEW_ID_INCREMENT: { + View nextFocus = NumberPicker.this.focusSearch(direction); + if (nextFocus != null) { + return nextFocus.createAccessibilityNodeInfo(); + } + return null; + } + } + } break; + case View.ACCESSIBILITY_FOCUS_UP: + case View.ACCESSIBILITY_FOCUS_BACKWARD: { + switch (mAccessibilityFocusedView) { + case UNDEFINED: { + return createAccessibilityNodeInfo(View.NO_ID); + } + case View.NO_ID: { + if (hasVirtualIncrementButton()) { + return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT); + } + } + //$FALL-THROUGH$ + case VIRTUAL_VIEW_ID_INCREMENT: { + return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT); + } + case VIRTUAL_VIEW_ID_INPUT: { + if (hasVirtualDecrementButton()) { + return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT); + } + } + //$FALL-THROUGH$ + case VIRTUAL_VIEW_ID_DECREMENT: { + View nextFocus = NumberPicker.this.focusSearch(direction); + if (nextFocus != null) { + return nextFocus.createAccessibilityNodeInfo(); + } + return null; + } + } + } break; + } + return null; + } + public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) { switch (virtualViewId) { case VIRTUAL_VIEW_ID_DECREMENT: { - sendAccessibilityEventForVirtualButton(virtualViewId, eventType, - getVirtualDecrementButtonText()); + if (hasVirtualDecrementButton()) { + sendAccessibilityEventForVirtualButton(virtualViewId, eventType, + getVirtualDecrementButtonText()); + } } break; case VIRTUAL_VIEW_ID_INPUT: { sendAccessibilityEventForVirtualText(eventType); } break; case VIRTUAL_VIEW_ID_INCREMENT: { - sendAccessibilityEventForVirtualButton(virtualViewId, eventType, - getVirtualIncrementButtonText()); + if (hasVirtualIncrementButton()) { + sendAccessibilityEventForVirtualButton(virtualViewId, eventType, + getVirtualIncrementButtonText()); + } } break; } } @@ -2227,8 +2433,13 @@ public class NumberPicker extends LinearLayout { private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() { AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo(); - info.setLongClickable(true); info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); + if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) { + info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); + } + if (mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT) { + info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); + } return info; } @@ -2252,6 +2463,15 @@ public class NumberPicker extends LinearLayout { getLocationOnScreen(locationOnScreen); boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); info.setBoundsInScreen(boundsInScreen); + + if (mAccessibilityFocusedView != virtualViewId) { + info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); + } + if (mAccessibilityFocusedView == virtualViewId) { + info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); + } + info.addAction(AccessibilityNodeInfo.ACTION_CLICK); + return info; } @@ -2261,10 +2481,16 @@ public class NumberPicker extends LinearLayout { info.setClassName(NumberPicker.class.getName()); info.setPackageName(mContext.getPackageName()); info.setSource(NumberPicker.this); - info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT); + + if (hasVirtualDecrementButton()) { + info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT); + } info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); - info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT); - info.setParent((View) getParent()); + if (hasVirtualIncrementButton()) { + info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT); + } + + info.setParent((View) getParentForAccessibility()); info.setEnabled(NumberPicker.this.isEnabled()); info.setScrollable(true); Rect boundsInParent = mTempRect; @@ -2276,9 +2502,31 @@ public class NumberPicker extends LinearLayout { getLocationOnScreen(locationOnScreen); boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); info.setBoundsInScreen(boundsInScreen); + + if (mAccessibilityFocusedView != View.NO_ID) { + info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); + } + if (mAccessibilityFocusedView == View.NO_ID) { + info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); + } + if (getWrapSelectorWheel() || getValue() < getMaxValue()) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + if (getWrapSelectorWheel() || getValue() > getMinValue()) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + return info; } + private boolean hasVirtualDecrementButton() { + return getWrapSelectorWheel() || getValue() > getMinValue(); + } + + private boolean hasVirtualIncrementButton() { + return getWrapSelectorWheel() || getValue() < getMaxValue(); + } + private String getVirtualDecrementButtonText() { int value = mValue - 1; if (mWrapSelectorWheel) { diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index b398ce4..a499743 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -742,6 +742,9 @@ public class ScrollView extends FrameLayout { @Override public boolean performAccessibilityAction(int action, Bundle arguments) { + if (super.performAccessibilityAction(action, arguments)) { + return true; + } switch (action) { case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { final int viewportHeight = getHeight() - mPaddingBottom - mPaddingTop; @@ -760,7 +763,7 @@ public class ScrollView extends FrameLayout { } } return false; } - return super.performAccessibilityAction(action, arguments); + return false; } @Override diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java index 21840ca..4045497 100644 --- a/core/java/android/widget/ShareActionProvider.java +++ b/core/java/android/widget/ShareActionProvider.java @@ -44,7 +44,6 @@ import com.android.internal.R; * <code> * // In Activity#onCreateOptionsMenu * public boolean onCreateOptionsMenu(Menu menu) { - * getManuInflater().inflate(R.menu.my_menu, menu); * // Get the menu item. * MenuItem menuItem = menu.findItem(R.id.my_menu_item); * // Get the provider and hold onto it to set/change the share intent. @@ -246,7 +245,7 @@ public class ShareActionProvider extends ActionProvider { * call {@link android.app.Activity#invalidateOptionsMenu()} to recreate the * action view. You should <strong>not</strong> call * {@link android.app.Activity#invalidateOptionsMenu()} from - * {@link android.app.Activity#onCreateOptionsMenu(Menu)}. + * {@link android.app.Activity#onCreateOptionsMenu(Menu)}." * <p> * <code> * private void doShare(Intent intent) { diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 7ca02e1..74ea038 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -132,8 +132,6 @@ public class SpellChecker implements SpellCheckerSessionListener { // Restore SpellCheckSpans in pool for (int i = 0; i < mLength; i++) { - // Resets id and progress to invalidate spell check span - mSpellCheckSpans[i].setSpellCheckInProgress(false); mIds[i] = -1; } mLength = 0; @@ -200,15 +198,16 @@ public class SpellChecker implements SpellCheckerSessionListener { private void addSpellCheckSpan(Editable editable, int start, int end) { final int index = nextSpellCheckSpanIndex(); - editable.setSpan(mSpellCheckSpans[index], start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + SpellCheckSpan spellCheckSpan = mSpellCheckSpans[index]; + editable.setSpan(spellCheckSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + spellCheckSpan.setSpellCheckInProgress(false); mIds[index] = mSpanSequenceCounter++; } - public void removeSpellCheckSpan(SpellCheckSpan spellCheckSpan) { + public void onSpellCheckSpanRemoved(SpellCheckSpan spellCheckSpan) { + // Recycle any removed SpellCheckSpan (from this code or during text edition) for (int i = 0; i < mLength; i++) { if (mSpellCheckSpans[i] == spellCheckSpan) { - // Resets id and progress to invalidate spell check span - mSpellCheckSpans[i].setSpellCheckInProgress(false); mIds[i] = -1; return; } @@ -387,6 +386,7 @@ public class SpellChecker implements SpellCheckerSessionListener { final SpellCheckSpan spellCheckSpan = onGetSuggestionsInternal(results[i], USE_SPAN_RANGE, USE_SPAN_RANGE); if (spellCheckSpan != null) { + // onSpellCheckSpanRemoved will recycle this span in the pool editable.removeSpan(spellCheckSpan); } } @@ -414,11 +414,12 @@ public class SpellChecker implements SpellCheckerSessionListener { suggestionsInfo, offset, length); if (spellCheckSpan == null && scs != null) { // the spellCheckSpan is shared by all the "SuggestionsInfo"s in the same - // SentenceSuggestionsInfo + // SentenceSuggestionsInfo. Removal is deferred after this loop. spellCheckSpan = scs; } } if (spellCheckSpan != null) { + // onSpellCheckSpanRemoved will recycle this span in the pool editable.removeSpan(spellCheckSpan); } } @@ -633,7 +634,8 @@ public class SpellChecker implements SpellCheckerSessionListener { } break; } - removeSpellCheckSpan(spellCheckSpan); + // This spellCheckSpan is replaced by the one we are creating + editable.removeSpan(spellCheckSpan); spellCheckStart = Math.min(spanStart, spellCheckStart); spellCheckEnd = Math.max(spanEnd, spellCheckEnd); } diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java index 22df3bc..dd0915b 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -32,6 +32,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.TableMaskFilter; +import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.InputDevice; @@ -1228,6 +1229,35 @@ public class StackView extends AdapterViewAnimator { public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(StackView.class.getName()); + info.setScrollable(getChildCount() > 1); + if (getDisplayedChild() < getChildCount() - 1) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + if (getDisplayedChild() > 0) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + } + + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + if (super.performAccessibilityAction(action, arguments)) { + return true; + } + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + if (getDisplayedChild() < getChildCount() - 1) { + showNext(); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + if (getDisplayedChild() > 0) { + showPrevious(); + return true; + } + } return false; + } + return false; } class LayoutParams extends ViewGroup.LayoutParams { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index abf2eb2..fc56e11 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -7240,7 +7240,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mEditor != null && mEditor.mSpellChecker != null && newStart < 0 && what instanceof SpellCheckSpan) { - mEditor.mSpellChecker.removeSpellCheckSpan((SpellCheckSpan) what); + mEditor.mSpellChecker.onSpellCheckSpanRemoved((SpellCheckSpan) what); } } diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index 89f2187..e9db9d9 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -19,13 +19,17 @@ package com.android.internal.app; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Intent; +import android.graphics.Typeface; +import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.Vibrator; -import android.view.MotionEvent; +import android.util.DisplayMetrics; +import android.view.Gravity; import android.view.View; -import android.view.ViewConfiguration; +import android.view.ViewGroup; import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; import android.widget.Toast; public class PlatLogoActivity extends Activity { @@ -34,15 +38,65 @@ public class PlatLogoActivity extends Activity { int mCount; final Handler mHandler = new Handler(); + private View makeView() { + DisplayMetrics metrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(metrics); + + LinearLayout view = new LinearLayout(this); + view.setOrientation(LinearLayout.VERTICAL); + view.setLayoutParams( + new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + final int p = (int)(8 * metrics.density); + view.setPadding(p, p, p, p); + + Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL); + Typeface normal = Typeface.create("sans-serif", Typeface.BOLD); + + final float size = 14 * metrics.density; + final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.CENTER_HORIZONTAL; + lp.bottomMargin = (int) (-4*metrics.density); + + TextView tv = new TextView(this); + if (light != null) tv.setTypeface(light); + tv.setTextSize(1.25f*size); + tv.setTextColor(0xFFFFFFFF); + tv.setShadowLayer(4*metrics.density, 0, 2*metrics.density, 0x66000000); + tv.setText("Android " + Build.VERSION.RELEASE); + view.addView(tv, lp); + + tv = new TextView(this); + if (normal != null) tv.setTypeface(normal); + tv.setTextSize(size); + tv.setTextColor(0xFFFFFFFF); + tv.setShadowLayer(4*metrics.density, 0, 2*metrics.density, 0x66000000); + tv.setText("JELLY BEAN"); + view.addView(tv, lp); + + return view; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mToast = Toast.makeText(this, "Android X.X: Jelly Bean", Toast.LENGTH_SHORT); + mToast = Toast.makeText(this, "", Toast.LENGTH_LONG); + mToast.setView(makeView()); + + DisplayMetrics metrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(metrics); mContent = new ImageView(this); mContent.setImageResource(com.android.internal.R.drawable.platlogo); mContent.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + + final int p = (int)(32 * metrics.density); + mContent.setPadding(p, p, p, p); mContent.setOnClickListener(new View.OnClickListener() { @Override diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp index 673c38d..c85b09c 100644 --- a/core/jni/android/graphics/TextLayoutCache.cpp +++ b/core/jni/android/graphics/TextLayoutCache.cpp @@ -332,15 +332,7 @@ uint32_t TextLayoutValue::getElapsedTime() { } TextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) { - mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal); - mArabicTypeface = NULL; - mHebrewRegularTypeface = NULL; - mHebrewBoldTypeface = NULL; - mBengaliTypeface = NULL; - mThaiTypeface = NULL; - mDevanagariRegularTypeface = NULL; - mTamilRegularTypeface = NULL; - mTamilBoldTypeface = NULL; + init(); mFontRec.klass = &harfbuzzSkiaClass; mFontRec.userData = 0; @@ -359,7 +351,19 @@ TextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) { mShaperItem.font->userData = &mShapingPaint; } -TextLayoutShaper::~TextLayoutShaper() { +void TextLayoutShaper::init() { + mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal); + mArabicTypeface = NULL; + mHebrewRegularTypeface = NULL; + mHebrewBoldTypeface = NULL; + mBengaliTypeface = NULL; + mThaiTypeface = NULL; + mDevanagariRegularTypeface = NULL; + mTamilRegularTypeface = NULL; + mTamilBoldTypeface = NULL; +} + +void TextLayoutShaper::unrefTypefaces() { SkSafeUnref(mDefaultTypeface); SkSafeUnref(mArabicTypeface); SkSafeUnref(mHebrewRegularTypeface); @@ -369,6 +373,10 @@ TextLayoutShaper::~TextLayoutShaper() { SkSafeUnref(mDevanagariRegularTypeface); SkSafeUnref(mTamilRegularTypeface); SkSafeUnref(mTamilBoldTypeface); +} + +TextLayoutShaper::~TextLayoutShaper() { + unrefTypefaces(); deleteShaperItemGlyphArrays(); } @@ -983,6 +991,12 @@ HB_Face TextLayoutShaper::getCachedHBFace(SkTypeface* typeface) { return face; } +void TextLayoutShaper::purgeCaches() { + mCachedHBFaces.clear(); + unrefTypefaces(); + init(); +} + TextLayoutEngine::TextLayoutEngine() { mShaper = new TextLayoutShaper(); #if USE_TEXT_LAYOUT_CACHE @@ -1018,6 +1032,10 @@ sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar void TextLayoutEngine::purgeCaches() { #if USE_TEXT_LAYOUT_CACHE mTextLayoutCache->clear(); + mShaper->purgeCaches(); +#if DEBUG_GLYPHS + ALOGD("Purged TextLayoutEngine caches"); +#endif #endif } diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h index 027e888..cb15a2a 100644 --- a/core/jni/android/graphics/TextLayoutCache.h +++ b/core/jni/android/graphics/TextLayoutCache.h @@ -169,6 +169,8 @@ public: void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags); + void purgeCaches(); + private: /** * Harfbuzz shaper item @@ -218,6 +220,9 @@ private: */ UnicodeString mBuffer; + void init(); + void unrefTypefaces(); + SkTypeface* typefaceForUnichar(const SkPaint* paint, SkTypeface* typeface, SkUnichar unichar, HB_Script script); diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index d8ec656..e3d11f2 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -357,19 +357,26 @@ static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject claz static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer, jintArray colors, jint offset, jint stride, jfloat left, jfloat top, jint width, jint height, jboolean hasAlpha, SkPaint* paint) { - SkBitmap bitmap; - SkBitmap::Config config = hasAlpha ? SkBitmap::kARGB_8888_Config : SkBitmap::kRGB_565_Config; - bitmap.setConfig(config, width, height); + SkBitmap* bitmap = new SkBitmap; + bitmap->setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : SkBitmap::kRGB_565_Config, + width, height); - if (!bitmap.allocPixels()) { + if (!bitmap->allocPixels()) { + delete bitmap; return; } - if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, bitmap)) { + if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap)) { + delete bitmap; return; } - renderer->drawBitmapData(&bitmap, left, top, paint); + renderer->drawBitmapData(bitmap, left, top, paint); + + // If the renderer is a deferred renderer it will own the bitmap + if (!renderer->isDeferred()) { + delete bitmap; + } } static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject clazz, diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml index 91e66bc..7b91022 100644 --- a/core/res/res/layout/time_picker_holo.xml +++ b/core/res/res/layout/time_picker_holo.xml @@ -44,6 +44,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" + android:importantForAccessibility="no" /> <!-- minute --> diff --git a/core/res/res/raw/accessibility_gestures.bin b/core/res/res/raw/accessibility_gestures.bin Binary files differindex f7e6615..96fa1ec 100644 --- a/core/res/res/raw/accessibility_gestures.bin +++ b/core/res/res/raw/accessibility_gestures.bin diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 25cfb7f..4ec0197 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -185,10 +185,10 @@ <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Bruge funktioner, der hurtigt kan dræne batteriet."</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string> <string name="permgroupdesc_calendar" msgid="5777534316982184416">"Direkte adgang til kalender og begivenheder."</string> - <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Læs brugerordbog"</string> - <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Læs ord i brugerordbogen."</string> - <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Skriv brugerordbog"</string> - <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Føj ord til brugerordbogen."</string> + <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Læse brugerordbog"</string> + <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Læse ord i brugerordbogen."</string> + <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Skrive brugerordbog"</string> + <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Føje ord til brugerordbogen."</string> <string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Bogmærker og historik"</string> <string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Direkte adgang til bogmærker og browserhistorik."</string> <string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Alarm"</string> @@ -561,7 +561,7 @@ <string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Tillader, at appen læser USB-lagerets indhold, herunder billeder og mediefiler."</string> <string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Tillader, at appen læser SD-kortets indhold, som kan omfatte billeder og mediefiler."</string> <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ændre eller slette indhold på USB-lager"</string> - <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"skift eller slet indholdet på dit SD-kort"</string> + <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"ændre eller slette indholdet på dit SD-kort"</string> <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Lader appen skrive til USB."</string> <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillader, at appen kan skrive til SD-kortet."</string> <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Rediger/slet internt medielagringsindhold"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 3d51570..4ca2b86 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1091,7 +1091,7 @@ <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"Bei der Verwendung Ihres USB-Speichers als USB-Massenspeicher ist ein Problem aufgetreten."</string> <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"Bei der Verwendung Ihrer SD-Karte als USB-Massenspeicher ist ein Problem aufgetreten."</string> <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-Verbindung"</string> - <string name="usb_storage_notification_message" msgid="939822783828183763">"Zum Kopieren von Dateien auf den/von dem Computer berühren"</string> + <string name="usb_storage_notification_message" msgid="939822783828183763">"Zum Kopieren von Dateien berühren"</string> <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB-Speicher deaktivieren"</string> <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"Zum Deaktivieren des USB-Speichers berühren"</string> <string name="usb_storage_stop_title" msgid="660129851708775853">"USB-Speicher in Verwendung"</string> @@ -1114,7 +1114,7 @@ <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Alle Daten auf Ihrer Karte gehen verloren."</string> <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string> <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging"</string> - <string name="adb_active_notification_message" msgid="1016654627626476142">"Zum Deaktivieren von USB-Debugging tippen"</string> + <string name="adb_active_notification_message" msgid="1016654627626476142">"Zum Deaktivieren von USB-Debugging berühren"</string> <string name="select_input_method" msgid="4653387336791222978">"Eingabemethode wählen"</string> <string name="configure_input_methods" msgid="9091652157722495116">"Eingabemethoden einrichten"</string> <string name="use_physical_keyboard" msgid="6203112478095117625">"Physische Tastatur"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 616b9be..5bca912 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -185,12 +185,9 @@ <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Menggunakan fitur yang dapat menguras baterai dengan cepat."</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string> <string name="permgroupdesc_calendar" msgid="5777534316982184416">"Akses langsung ke kalender dan acara."</string> - <!-- no translation found for permgrouplab_dictionary (4148597128843641379) --> - <skip /> - <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) --> - <skip /> - <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) --> - <skip /> + <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Membaca Kamus Pengguna"</string> + <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Membaca kata dalam kamus pengguna."</string> + <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Menulis Kamus Pengguna"</string> <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Menambahkan kata ke kamus pengguna."</string> <string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Bookmark dan Riwayat"</string> <string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Akses langsung ke bookmark dan riwayat browser."</string> @@ -564,8 +561,7 @@ <string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Izinkan aplikasi membaca konten penyimpanan USB, yang mungkin mencakup foto dan media."</string> <string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Izinkan aplikasi membaca konten kartu SD, yang mungkin mencakup foto dan media."</string> <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ubah/hapus konten pympanan USB"</string> - <!-- no translation found for permlab_sdcardWrite (8805693630050458763) --> - <skip /> + <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"mengubah atau menghapus konten kartu SD Anda"</string> <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Mengizinkan apl menulis ke penyimpanan USB."</string> <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Memungkinkan apl menulis ke kartu SD."</string> <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ubah/hapus konten penyimpanan media internal"</string> diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml index c5727ea..d26666e 100644 --- a/core/res/res/values-sw600dp/dimens.xml +++ b/core/res/res/values-sw600dp/dimens.xml @@ -51,12 +51,6 @@ <!-- Size of status line font in LockScreen. --> <dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen> - <!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. --> - <dimen name="default_app_widget_padding_left">12dp</dimen> - <dimen name="default_app_widget_padding_top">4dp</dimen> - <dimen name="default_app_widget_padding_right">12dp</dimen> - <dimen name="default_app_widget_padding_bottom">20dp</dimen> - <!-- Minimum width for an action button in the menu area of an action bar --> <dimen name="action_button_min_width">64dip</dimen> diff --git a/core/res/res/values-sw720dp/dimens.xml b/core/res/res/values-sw720dp/dimens.xml index 34c7ea3..fc336ae 100644 --- a/core/res/res/values-sw720dp/dimens.xml +++ b/core/res/res/values-sw720dp/dimens.xml @@ -50,6 +50,12 @@ <dimen name="preference_screen_header_padding_side">0dip</dimen> <integer name="preference_screen_header_scrollbarStyle">0x0</integer> <!-- insideOverlay --> + <!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. --> + <dimen name="default_app_widget_padding_left">12dp</dimen> + <dimen name="default_app_widget_padding_top">4dp</dimen> + <dimen name="default_app_widget_padding_right">12dp</dimen> + <dimen name="default_app_widget_padding_bottom">20dp</dimen> + <!-- Preference fragment padding, sides --> <dimen name="preference_fragment_padding_side">32dp</dimen> <!-- Padding to the left of the preference panel breadcrumb --> diff --git a/core/res/res/values-w500dp/bools.xml b/core/res/res/values-w500dp/bools.xml deleted file mode 100644 index f53fd39..0000000 --- a/core/res/res/values-w500dp/bools.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - <bool name="activity_chooser_view_has_default_activity">true</bool> -</resources>
\ No newline at end of file diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml index 6910ebe..f9762b1 100644 --- a/core/res/res/values/bools.xml +++ b/core/res/res/values/bools.xml @@ -22,5 +22,4 @@ <bool name="show_ongoing_ime_switcher">true</bool> <bool name="action_bar_expanded_action_views_exclusive">true</bool> <bool name="target_honeycomb_needs_options_menu">true</bool> - <bool name="activity_chooser_view_has_default_activity">false</bool> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 48038dd..a24e345 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1380,7 +1380,6 @@ <java-symbol type="bool" name="config_wifi_dual_band_support" /> <java-symbol type="bool" name="config_wimaxEnabled" /> <java-symbol type="bool" name="show_ongoing_ime_switcher" /> - <java-symbol type="bool" name="activity_chooser_view_has_default_activity" /> <java-symbol type="color" name="config_defaultNotificationColor" /> <java-symbol type="drawable" name="ic_notification_ime_default" /> <java-symbol type="drawable" name="stat_notify_car_mode" /> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java index f7b0cd0..f01562c 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java @@ -244,8 +244,13 @@ public class ConnectivityManagerTestActivity extends Activity { mContext = this; mChannel = mWifiManager.initialize(mContext, mContext.getMainLooper(), null); - initializeNetworkStates(); + if (mWifiManager.isWifiApEnabled()) { + // if soft AP is enabled, disable it + mWifiManager.setWifiApEnabled(null, false); + log("Disable soft ap"); + } + initializeNetworkStates(); log("Clear Wifi before we start the test."); removeConfiguredNetworksAndDisableWifi(); mWifiRegexs = mCM.getTetherableWifiRegexs(); 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 7e136be..60595fb 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java @@ -103,7 +103,7 @@ public class WifiApStress assertTrue(mAct.mWifiManager.setWifiApEnabled(config, true)); // Wait for wifi ap state to be ENABLED assertTrue(mAct.waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED, - ConnectivityManagerTestActivity.LONG_TIMEOUT)); + 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT)); // Wait for wifi tethering result assertEquals(ConnectivityManagerTestActivity.SUCCESS, mAct.waitForTetherStateChange(2*ConnectivityManagerTestActivity.SHORT_TIMEOUT)); 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 649ec3e..39e2cf2 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java @@ -83,6 +83,7 @@ public class WifiStressTest @Override public void setUp() throws Exception { super.setUp(); + mAct = getActivity(); mRunner = (ConnectivityManagerStressTestRunner) getInstrumentation(); mReconnectIterations = mRunner.mReconnectIterations; @@ -97,11 +98,6 @@ public class WifiStressTest mOutputWriter = new BufferedWriter(new FileWriter(new File( Environment.getExternalStorageDirectory(), OUTPUT_FILE), true)); mAct.turnScreenOn(); - if (mAct.mWifiManager.isWifiApEnabled()) { - // if soft AP is enabled, disable it - assertTrue(mAct.mWifiManager.setWifiApEnabled(null, false)); - Log.v(TAG, "disable soft ap"); - } if (!mAct.mWifiManager.isWifiEnabled()) { log("Enable wi-fi before stress tests."); if (!mAct.enableWifi()) { diff --git a/core/tests/utillib/src/android/test/BandwidthTestCase.java b/core/tests/utillib/src/android/test/BandwidthTestCase.java index 4f95f77..c03d9b3 100644 --- a/core/tests/utillib/src/android/test/BandwidthTestCase.java +++ b/core/tests/utillib/src/android/test/BandwidthTestCase.java @@ -18,6 +18,7 @@ package android.test; import android.net.NetworkStats; import android.net.TrafficStats; import android.os.Bundle; +import android.util.Log; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -29,6 +30,7 @@ import java.lang.reflect.Modifier; * as an {@link InstrumentationTestCase} */ public class BandwidthTestCase extends InstrumentationTestCase { + private static final String TAG = "BandwidthTestCase"; private static final String REPORT_KEY_PACKETS_SENT = "txPackets"; private static final String REPORT_KEY_PACKETS_RECEIVED = "rxPackets"; private static final String REPORT_KEY_BYTES_SENT = "txBytes"; @@ -86,11 +88,26 @@ public class BandwidthTestCase extends InstrumentationTestCase { } } else if (method.isAnnotationPresent(BandwidthTest.class) || testClass.isAnnotationPresent(BandwidthTest.class)) { - TrafficStats.startDataProfiling(null); + /** + * If bandwidth profiling fails for whatever reason the test + * should be allow to execute to its completion. + * Typically bandwidth profiling would fail when a lower level + * component is missing, such as the kernel module, for a newly + * introduced hardware. + */ + try{ + TrafficStats.startDataProfiling(null); + } catch(IllegalStateException isx){ + Log.w(TAG, "Failed to start bandwidth profiling"); + } runMethod(method, 1, false); - NetworkStats stats = TrafficStats.stopDataProfiling(null); - NetworkStats.Entry entry = stats.getTotal(null); - getInstrumentation().sendStatus(2, getBandwidthStats(entry)); + try{ + NetworkStats stats = TrafficStats.stopDataProfiling(null); + NetworkStats.Entry entry = stats.getTotal(null); + getInstrumentation().sendStatus(2, getBandwidthStats(entry)); + } catch (IllegalStateException isx){ + Log.w(TAG, "Failed to collect bandwidth stats"); + } } else { runMethod(method, runCount, isRepetitive); } diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd index b33a097..847681b 100644 --- a/docs/html/guide/topics/resources/providing-resources.jd +++ b/docs/html/guide/topics/resources/providing-resources.jd @@ -528,20 +528,22 @@ how this affects your application during runtime.</p> which indicates the current device orientation.</p> </td> </tr> - <tr id="DockQualifier"> - <td>Dock mode</td> + <tr id="UiModeQualifier"> + <td>UI mode</td> <td> <code>car</code><br/> - <code>desk</code> + <code>desk</code><br/> + <code>television</code> </td> <td> <ul class="nolist"> - <li>{@code car}: Device is in a car dock</li> - <li>{@code desk}: Device is in a desk dock</li> + <li>{@code car}: Device is displaying in a car dock</li> + <li>{@code desk}: Device is displaying in a desk dock</li> + <li>{@code television}: Device is displaying on a television</li> </ul> - <p><em>Added in API level 8.</em></p> + <p><em>Added in API level 8, television added in API 13.</em></p> <p>This can change during the life of your application if the user places the device in a -dock. You can enable or disable this mode using {@link +dock. You can enable or disable some of these modes using {@link android.app.UiModeManager}. See <a href="runtime-changes.html">Handling Runtime Changes</a> for information about how this affects your application during runtime.</p> </td> diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index d2a6a7a..a5f653a 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -162,6 +162,13 @@ void DisplayList::clearResources() { } mBitmapResources.clear(); + for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) { + SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i); + caches.resourceCache.decrementRefcount(bitmap); + caches.resourceCache.destructor(bitmap); + } + mOwnedBitmapResources.clear(); + for (size_t i = 0; i < mFilterResources.size(); i++) { caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i)); } @@ -217,44 +224,51 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde Caches& caches = Caches::getInstance(); - const Vector<SkBitmap*> &bitmapResources = recorder.getBitmapResources(); + const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources(); for (size_t i = 0; i < bitmapResources.size(); i++) { SkBitmap* resource = bitmapResources.itemAt(i); mBitmapResources.add(resource); caches.resourceCache.incrementRefcount(resource); } - const Vector<SkiaColorFilter*> &filterResources = recorder.getFilterResources(); + const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources(); + for (size_t i = 0; i < ownedBitmapResources.size(); i++) { + SkBitmap* resource = ownedBitmapResources.itemAt(i); + mOwnedBitmapResources.add(resource); + caches.resourceCache.incrementRefcount(resource); + } + + const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources(); for (size_t i = 0; i < filterResources.size(); i++) { SkiaColorFilter* resource = filterResources.itemAt(i); mFilterResources.add(resource); caches.resourceCache.incrementRefcount(resource); } - const Vector<SkiaShader*> &shaders = recorder.getShaders(); + const Vector<SkiaShader*>& shaders = recorder.getShaders(); for (size_t i = 0; i < shaders.size(); i++) { SkiaShader* resource = shaders.itemAt(i); mShaders.add(resource); caches.resourceCache.incrementRefcount(resource); } - const Vector<SkPaint*> &paints = recorder.getPaints(); + const Vector<SkPaint*>& paints = recorder.getPaints(); for (size_t i = 0; i < paints.size(); i++) { mPaints.add(paints.itemAt(i)); } - const Vector<SkPath*> &paths = recorder.getPaths(); + const Vector<SkPath*>& paths = recorder.getPaths(); for (size_t i = 0; i < paths.size(); i++) { mPaths.add(paths.itemAt(i)); } - const SortedVector<SkPath*> &sourcePaths = recorder.getSourcePaths(); + const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths(); for (size_t i = 0; i < sourcePaths.size(); i++) { mSourcePaths.add(sourcePaths.itemAt(i)); caches.resourceCache.incrementRefcount(sourcePaths.itemAt(i)); } - const Vector<SkMatrix*> &matrices = recorder.getMatrices(); + const Vector<SkMatrix*>& matrices = recorder.getMatrices(); for (size_t i = 0; i < matrices.size(); i++) { mMatrices.add(matrices.itemAt(i)); } @@ -1036,10 +1050,7 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], bitmap, x, y, paint); - if (bitmap) { - renderer.drawBitmap(bitmap, x, y, paint); - delete bitmap; - } + renderer.drawBitmap(bitmap, x, y, paint); } break; case DrawBitmapMesh: { @@ -1295,6 +1306,12 @@ void DisplayListRenderer::reset() { } mBitmapResources.clear(); + for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) { + SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i); + caches.resourceCache.decrementRefcount(bitmap); + } + mOwnedBitmapResources.clear(); + for (size_t i = 0; i < mFilterResources.size(); i++) { caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i)); } @@ -1336,6 +1353,10 @@ DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) { return displayList; } +bool DisplayListRenderer::isDeferred() { + return true; +} + void DisplayListRenderer::setViewport(int width, int height) { mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 2f74f5b..93b065d 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -398,7 +398,6 @@ public: private: void init(); - void initProperties(); void clearResources(); @@ -424,16 +423,7 @@ private: } SkBitmap* getBitmapData() { - SkBitmap* bitmap = new SkBitmap; - bitmap->setConfig((SkBitmap::Config) getInt(), getInt(), getInt()); - if (!bitmap->allocPixels()) { - delete bitmap; - return NULL; - } - - bitmap->setPixels((void*) mReader.skip(bitmap->height() * bitmap->rowBytes())); - - return bitmap; + return (SkBitmap*) getInt(); } SkiaShader* getShader() { @@ -497,6 +487,7 @@ private: } Vector<SkBitmap*> mBitmapResources; + Vector<SkBitmap*> mOwnedBitmapResources; Vector<SkiaColorFilter*> mFilterResources; Vector<SkPaint*> mPaints; @@ -552,6 +543,8 @@ public: ANDROID_API DisplayList* getDisplayList(DisplayList* displayList); + virtual bool isDeferred(); + virtual void setViewport(int width, int height); virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque); virtual void finish(); @@ -634,6 +627,10 @@ public: return mBitmapResources; } + const Vector<SkBitmap*>& getOwnedBitmapResources() const { + return mOwnedBitmapResources; + } + const Vector<SkiaColorFilter*>& getFilterResources() const { return mFilterResources; } @@ -719,17 +716,6 @@ private: mWriter.write(values, count * sizeof(int32_t)); } - void addBitmapData(SkBitmap* bitmap) { - mWriter.writeInt(bitmap->config()); - mWriter.writeInt(bitmap->width()); - mWriter.writeInt(bitmap->height()); - - SkAutoLockPixels alp(*bitmap); - void* src = bitmap->getPixels(); - - mWriter.write(src, bitmap->rowBytes() * bitmap->height()); - } - void addUInts(const uint32_t* values, int8_t count) { mWriter.writeInt(count); mWriter.write(values, count * sizeof(uint32_t)); @@ -825,6 +811,12 @@ private: Caches::getInstance().resourceCache.incrementRefcount(bitmap); } + void addBitmapData(SkBitmap* bitmap) { + addInt((int) bitmap); + mOwnedBitmapResources.add(bitmap); + Caches::getInstance().resourceCache.incrementRefcount(bitmap); + } + inline void addShader(SkiaShader* shader) { if (!shader) { addInt((int) NULL); @@ -851,6 +843,7 @@ private: } Vector<SkBitmap*> mBitmapResources; + Vector<SkBitmap*> mOwnedBitmapResources; Vector<SkiaColorFilter*> mFilterResources; Vector<SkPaint*> mPaints; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 7f242c3..50f5d57 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -144,6 +144,10 @@ uint32_t OpenGLRenderer::getStencilSize() { return STENCIL_BUFFER_SIZE; } +bool OpenGLRenderer::isDeferred() { + return false; +} + void OpenGLRenderer::setViewport(int width, int height) { mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 0ea0db7..ab324ff 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -63,6 +63,8 @@ public: ANDROID_API OpenGLRenderer(); virtual ~OpenGLRenderer(); + virtual bool isDeferred(); + virtual void setViewport(int width, int height); ANDROID_API void prepare(bool opaque); diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 9ffad88..cf5f822 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -59,11 +59,11 @@ void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) { SkSafeRef(bitmapResource->pixelRef()); SkSafeRef(bitmapResource->getColorTable()); - incrementRefcount((void*)bitmapResource, kBitmap); + incrementRefcount((void*) bitmapResource, kBitmap); } void ResourceCache::incrementRefcount(SkPath* pathResource) { - incrementRefcount((void*)pathResource, kPath); + incrementRefcount((void*) pathResource, kPath); } void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index bc144bb..4cff67b 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -48,7 +48,7 @@ android:id="@+id/latestItems" android:layout_width="match_parent" android:layout_height="wrap_content" - systemui:rowHeight="@dimen/notification_height" + systemui:rowHeight="@dimen/notification_row_min_height" /> </ScrollView> @@ -68,4 +68,4 @@ </com.android.systemui.statusbar.phone.CloseDragHandle> -</FrameLayout><!-- end of sliding panel -->
\ No newline at end of file +</FrameLayout><!-- end of sliding panel --> diff --git a/packages/SystemUI/res/layout/system_bar_notification_panel.xml b/packages/SystemUI/res/layout/system_bar_notification_panel.xml index 42af147..5579505 100644 --- a/packages/SystemUI/res/layout/system_bar_notification_panel.xml +++ b/packages/SystemUI/res/layout/system_bar_notification_panel.xml @@ -77,7 +77,7 @@ android:clickable="true" android:focusable="true" android:descendantFocusability="afterDescendants" - systemui:rowHeight="@dimen/notification_height" + systemui:rowHeight="@dimen/notification_row_min_height" /> </ScrollView> </LinearLayout> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 46adfd7..aae070a 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -26,7 +26,7 @@ <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"सूची से निकालें"</string> <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"एप्लिकेशन जानकारी"</string> <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"कोई हाल ही के एप्लिकेशन नहीं"</string> - <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"हाल ही के एप्लिकेशन ख़ारिज करें"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"हाल ही के एप्लिकेशन खारिज करें"</string> <plurals name="status_bar_accessibility_recent_apps"> <item quantity="one" msgid="5854176083865845541">"1 हाल ही का एप्लिकेशन"</item> <item quantity="other" msgid="1040784359794890744">"%d हाल ही के एप्लिकेशन"</item> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index a117252..a69fc23 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -141,8 +141,7 @@ <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktifkan tirai layar"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info aplikasi"</string> <string name="notifications_off_title" msgid="8936620513608443224">"Pemberitahuan mati"</string> - <!-- no translation found for notifications_off_text (2529001315769385273) --> - <skip /> + <string name="notifications_off_text" msgid="2529001315769385273">"Ketuk di sini untuk menyalakan pemberitahuan lagi."</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Layar akan diputar secara otomatis."</string> <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Layar dikunci dalam orientasi lanskap."</string> <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Layar dikunci dalam orientasi potret."</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 3277fb6..7a7d08f 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -38,7 +38,7 @@ <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена."</string> <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g>"</string> <string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается."\n"Используйте только зарядное устройство из комплекта поставки."</string> - <string name="battery_low_why" msgid="7279169609518386372">"Расход заряда батареи"</string> + <string name="battery_low_why" msgid="7279169609518386372">"Подробнее"</string> <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string> <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим полета"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 5026d6d..1fa3b21 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -141,7 +141,7 @@ <string name="dreams_dock_launcher" msgid="3541196417659166245">"Vklop ohranjevalnika zaslona"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Podatki o aplikaciji"</string> <string name="notifications_off_title" msgid="8936620513608443224">"Obvestila so izklopljena"</string> - <string name="notifications_off_text" msgid="2529001315769385273">"Dotaknite se tukaj, da spet vklopite obvestila."</string> + <string name="notifications_off_text" msgid="2529001315769385273">"Dotaknite se tukaj, da ponovno vklopite obvestila."</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon se bo samodejno zasukal."</string> <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Zaslon je zaklenjen v ležeči usmerjenosti."</string> <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Zaslon je zaklenjen v pokončni usmerjenosti."</string> diff --git a/packages/SystemUI/res/values-xhdpi/dimens.xml b/packages/SystemUI/res/values-xhdpi/dimens.xml deleted file mode 100644 index 303841a..0000000 --- a/packages/SystemUI/res/values-xhdpi/dimens.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?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. -*/ ---> -<resources> - <!-- thickness (height) of each notification row, including any separators or padding --> - <!-- note: this is the same value as in values/dimens.xml; the value is overridden in - values-hdpi/dimens.xml and so we need to re-assert the general value here --> - <dimen name="notification_height">68dp</dimen> - - <!-- thickness (height) of dividers between each notification row --> - <!-- same as in values/dimens.xml; see note at notification_height --> - <dimen name="notification_divider_height">2dp</dimen> -</resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 8293d99..4f3e787 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -142,7 +142,7 @@ <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Ulwazi lohlelo lokusebenza"</string> <string name="notifications_off_title" msgid="8936620513608443224">"Izaziso zivaliwe"</string> <string name="notifications_off_text" msgid="2529001315769385273">"Thepha lapha ukuvula futhi izaziso."</string> - <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Isikrini sizophenduka ngokuzanzakalela."</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Isikrini sizophenduka ngokuzenzakalela."</string> <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Isikrini sikhiyelwe ngomumo we-landscape."</string> <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Isikrini sikhiyelwe ngomumo we-portrait."</string> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f548166..9042045 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -49,18 +49,21 @@ reducing false presses on navbar buttons; approx 2mm --> <dimen name="navigation_bar_deadzone_size">12dp</dimen> - <!-- thickness (height) of each 1U notification row plus glow, padding, etc --> - <dimen name="notification_height">72dp</dimen> - <!-- Height of notification icons in the status bar --> <dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen> - <!-- Height of a small notification in the status bar plus glow, padding, etc --> - <dimen name="notification_min_height">72dp</dimen> + <!-- Height of a small notification in the status bar --> + <dimen name="notification_min_height">64dp</dimen> <!-- Height of a large notification in the status bar --> <dimen name="notification_max_height">256dp</dimen> + <!-- Height of a small notification in the status bar plus glow, padding, etc --> + <dimen name="notification_row_min_height">72dp</dimen> + + <!-- Height of a large notification in the status bar plus glow, padding, etc --> + <dimen name="notification_row_max_height">260dp</dimen> + <!-- size at which Notification icons will be drawn in the status bar --> <dimen name="status_bar_icon_drawing_size">18dip</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index 9e273d4..3502b62 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -41,7 +41,7 @@ import java.util.HashMap; */ public class RingtonePlayer extends SystemUI { private static final String TAG = "RingtonePlayer"; - private static final boolean LOGD = true; + private static final boolean LOGD = false; // TODO: support Uri switching under same IBinder diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 71d26b5..4b223dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -478,7 +478,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) { int rowHeight = - mContext.getResources().getDimensionPixelSize(R.dimen.notification_height); + mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height); int minHeight = mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height); int maxHeight = @@ -498,7 +498,6 @@ public abstract class BaseStatusBar extends SystemUI implements // for blaming (see SwipeHelper.setLongPressListener) row.setTag(sbn.pkg); - ViewGroup.LayoutParams lp = row.getLayoutParams(); workAroundBadLayerDrawableOpacity(row); View vetoButton = updateNotificationVetoButton(row, sbn); vetoButton.setContentDescription(mContext.getString( @@ -510,13 +509,6 @@ public abstract class BaseStatusBar extends SystemUI implements ViewGroup content = (ViewGroup)row.findViewById(R.id.content); ViewGroup adaptive = (ViewGroup)row.findViewById(R.id.adaptive); - // Ensure that R.id.content is properly set to 64dp high if 1U - lp = content.getLayoutParams(); - if (large == null) { - lp.height = minHeight; - } - content.setLayoutParams(lp); - content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); PendingIntent contentIntent = sbn.notification.contentIntent; @@ -528,6 +520,7 @@ public abstract class BaseStatusBar extends SystemUI implements content.setOnClickListener(null); } + // TODO(cwren) normalize variable names with those in updateNotification View expandedOneU = null; View expandedLarge = null; Exception exception = null; @@ -556,7 +549,7 @@ public abstract class BaseStatusBar extends SystemUI implements SizeAdaptiveLayout.LayoutParams params = new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams()); params.minHeight = minHeight+1; - params.maxHeight = SizeAdaptiveLayout.LayoutParams.UNBOUNDED; + params.maxHeight = maxHeight; adaptive.addView(expandedLarge, params); } row.setDrawingCacheEnabled(true); @@ -723,20 +716,18 @@ public abstract class BaseStatusBar extends SystemUI implements } protected boolean expandView(NotificationData.Entry entry, boolean expand) { - if (entry.expandable()) { - int rowHeight = - mContext.getResources().getDimensionPixelSize(R.dimen.notification_height); - ViewGroup.LayoutParams lp = entry.row.getLayoutParams(); - if (expand) { - lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; - } else { - lp.height = rowHeight; - } - entry.row.setLayoutParams(lp); - return expand; + int rowHeight = + mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height); + ViewGroup.LayoutParams lp = entry.row.getLayoutParams(); + if (entry.expandable() && expand) { + if (DEBUG) Slog.d(TAG, "setting expanded row height to WRAP_CONTENT"); + lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; } else { - return false; + if (DEBUG) Slog.d(TAG, "setting collapsed row height to " + rowHeight); + lp.height = rowHeight; } + entry.row.setLayoutParams(lp); + return expand; } protected void updateExpansionStates() { @@ -781,32 +772,41 @@ public abstract class BaseStatusBar extends SystemUI implements final StatusBarNotification oldNotification = oldEntry.notification; // XXX: modify when we do something more intelligent with the two content views - final RemoteViews oldContentView = (oldNotification.notification.bigContentView != null) - ? oldNotification.notification.bigContentView - : oldNotification.notification.contentView; - final RemoteViews contentView = (notification.notification.bigContentView != null) - ? notification.notification.bigContentView - : notification.notification.contentView; + final RemoteViews oldContentView = oldNotification.notification.contentView; + final RemoteViews contentView = notification.notification.contentView; + final RemoteViews oldBigContentView = oldNotification.notification.bigContentView; + final RemoteViews bigContentView = notification.notification.bigContentView; if (DEBUG) { Slog.d(TAG, "old notification: when=" + oldNotification.notification.when + " ongoing=" + oldNotification.isOngoing() + " expanded=" + oldEntry.expanded + " contentView=" + oldContentView + + " bigContentView=" + oldBigContentView + " rowParent=" + oldEntry.row.getParent()); Slog.d(TAG, "new notification: when=" + notification.notification.when + " ongoing=" + oldNotification.isOngoing() - + " contentView=" + contentView); + + " contentView=" + contentView + + " bigContentView=" + bigContentView); } // Can we just reapply the RemoteViews in place? If when didn't change, the order // didn't change. + + // 1U is never null boolean contentsUnchanged = oldEntry.expanded != null - && contentView != null && oldContentView != null && contentView.getPackage() != null && oldContentView.getPackage() != null && oldContentView.getPackage().equals(contentView.getPackage()) && oldContentView.getLayoutId() == contentView.getLayoutId(); + // large view may be null + boolean bigContentsUnchanged = + (oldEntry.getLargeView() == null && bigContentView == null) + || ((oldEntry.getLargeView() != null && bigContentView != null) + && bigContentView.getPackage() != null + && oldBigContentView.getPackage() != null + && oldBigContentView.getPackage().equals(bigContentView.getPackage()) + && oldBigContentView.getLayoutId() == bigContentView.getLayoutId()); ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent(); boolean orderUnchanged = notification.notification.when==oldNotification.notification.when && notification.score == oldNotification.score; @@ -816,12 +816,15 @@ public abstract class BaseStatusBar extends SystemUI implements && !TextUtils.equals(notification.notification.tickerText, oldEntry.notification.notification.tickerText); boolean isTopAnyway = isTopNotification(rowParent, oldEntry); - if (contentsUnchanged && (orderUnchanged || isTopAnyway)) { + if (contentsUnchanged && bigContentsUnchanged && (orderUnchanged || isTopAnyway)) { if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key); oldEntry.notification = notification; try { // Reapply the RemoteViews - contentView.reapply(mContext, oldEntry.content); + contentView.reapply(mContext, oldEntry.expanded); + if (bigContentView != null && oldEntry.getLargeView() != null) { + bigContentView.reapply(mContext, oldEntry.getLargeView()); + } // update the contentIntent final PendingIntent contentIntent = notification.notification.contentIntent; if (contentIntent != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java index 0fe7a0a..f41d99c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java @@ -101,8 +101,8 @@ public class NotificationRowLayout float densityScale = getResources().getDisplayMetrics().density; float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); - int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); - int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height); + int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height); + int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height); mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight); } diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java index 06cd69e..203f9db 100644 --- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -113,10 +113,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mPasswordEntry.setOnEditorActionListener(this); mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this, false); - mKeyboardHelper.setEnableHaptics( - Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, 0) - != 0); + mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled()); boolean imeOrDeleteButtonVisible = false; if (mIsAlpha) { // We always use the system IME for alpha keyboard, so hide lockscreen's soft keyboard diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index cc7050a..9629f0a 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -79,6 +79,7 @@ import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; import android.view.ViewManager; +import android.view.ViewParent; import android.view.ViewStub; import android.view.Window; import android.view.WindowManager; @@ -582,7 +583,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { st.decorView.setWindowBackground(getContext().getResources().getDrawable( backgroundResId)); - + ViewParent shownPanelParent = st.shownPanelView.getParent(); + if (shownPanelParent != null && shownPanelParent instanceof ViewGroup) { + ((ViewGroup) shownPanelParent).removeView(st.shownPanelView); + } st.decorView.addView(st.shownPanelView, lp); /* diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java index 889fbe4..3fbac38 100644 --- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -20,6 +20,7 @@ import com.android.server.accessibility.TouchExplorer.GestureListener; import com.android.server.input.InputFilter; import android.content.Context; +import android.os.PowerManager; import android.util.Slog; import android.view.InputDevice; import android.view.InputEvent; @@ -37,6 +38,8 @@ public class AccessibilityInputFilter extends InputFilter { private final Context mContext; + private final PowerManager mPm; + private final GestureListener mGestureListener; /** @@ -74,6 +77,7 @@ public class AccessibilityInputFilter extends InputFilter { super(context.getMainLooper()); mContext = context; mGestureListener = gestureListener; + mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); } @Override @@ -108,6 +112,7 @@ public class AccessibilityInputFilter extends InputFilter { mTouchExplorer.clear(motionEvent, policyFlags); } if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) != 0) { + mPm.userActivity(event.getEventTime(), false); mTouchExplorer.onMotionEvent(motionEvent, policyFlags); } else { mTouchExplorer.clear(motionEvent, policyFlags); diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 28ce1df..1937bad 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -25,6 +25,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceClient; import android.accessibilityservice.IAccessibilityServiceConnection; import android.app.PendingIntent; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -1343,7 +1344,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub sendDownAndUpKeyEvents(KeyEvent.KEYCODE_APP_SWITCH); } return true; case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: { - // TODO: Implement when 6346026 is fixed. + expandStatusBar(); } return true; } return false; @@ -1413,6 +1414,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub Binder.restoreCallingIdentity(token); } + private void expandStatusBar() { + final long token = Binder.clearCallingIdentity(); + + StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService( + android.app.Service.STATUS_BAR_SERVICE); + statusBarManager.expand(); + + Binder.restoreCallingIdentity(token); + } + private IAccessibilityInteractionConnection getConnectionLocked(int windowId) { if (DEBUG) { Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 54ef724..76016f4 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3510,31 +3510,36 @@ public final class ActivityManagerService extends ActivityManagerNative public void closeSystemDialogs(String reason) { enforceNotIsolatedCaller("closeSystemDialogs"); + + final int uid = Binder.getCallingUid(); + final long origId = Binder.clearCallingIdentity(); + synchronized (this) { + closeSystemDialogsLocked(uid, reason); + } + Binder.restoreCallingIdentity(origId); + } + + void closeSystemDialogsLocked(int callingUid, String reason) { Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); if (reason != null) { intent.putExtra("reason", reason); } + mWindowManager.closeSystemDialogs(reason); - final int uid = Binder.getCallingUid(); - final long origId = Binder.clearCallingIdentity(); - synchronized (this) { - mWindowManager.closeSystemDialogs(reason); - - for (int i=mMainStack.mHistory.size()-1; i>=0; i--) { - ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); - if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) { - r.stack.finishActivityLocked(r, i, - Activity.RESULT_CANCELED, null, "close-sys"); - } + for (int i=mMainStack.mHistory.size()-1; i>=0; i--) { + ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); + if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) { + r.stack.finishActivityLocked(r, i, + Activity.RESULT_CANCELED, null, "close-sys"); } - - broadcastIntentLocked(null, null, intent, null, - null, 0, null, null, null, false, false, -1, uid, 0 /* TODO: Verify */); } - Binder.restoreCallingIdentity(origId); + + broadcastIntentLocked(null, null, intent, null, + null, 0, null, null, null, false, false, -1, + callingUid, 0 /* TODO: Verify */); } - + public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids) throws RemoteException { enforceNotIsolatedCaller("getProcessMemoryInfo"); diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index b9f63cf..5b15e50 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -52,6 +52,7 @@ import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserId; @@ -2532,6 +2533,10 @@ final class ActivityStack { mDismissKeyguardOnNextActivity = false; mService.mWindowManager.dismissKeyguard(); } + if (err >= ActivityManager.START_SUCCESS && + (launchFlags&Intent.FLAG_ACTIVITY_CLOSE_SYSTEM_DIALOGS) != 0) { + mService.closeSystemDialogsLocked(Process.myUid(), "launch"); + } return err; } @@ -2619,6 +2624,7 @@ final class ActivityStack { } boolean addingToTask = false; + boolean movedHome = false; TaskRecord reuseTask = null; if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) @@ -2657,6 +2663,7 @@ final class ActivityStack { if (callerAtFront) { // We really do want to push this one into the // user's face, right now. + movedHome = true; moveHomeToFrontFromLaunchLocked(launchFlags); moveTaskToFrontLocked(taskTop.task, r, options); } @@ -2835,7 +2842,9 @@ final class ActivityStack { r.setTask(reuseTask, reuseTask, true); } newTask = true; - moveHomeToFrontFromLaunchLocked(launchFlags); + if (!movedHome) { + moveHomeToFrontFromLaunchLocked(launchFlags); + } } else if (sourceRecord != null) { if (!addingToTask && @@ -3543,7 +3552,7 @@ final class ActivityStack { } ActivityRecord r = mHistory.get(index); - while (index > 0) { + while (index >= 0) { ActivityRecord cur = mHistory.get(index); if (cur.task != r.task) { break; diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index cba92f3..5516dea 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -935,6 +935,59 @@ class WindowStateAnimator { mDtDy = mWin.mGlobalScale; } + void updateSurfaceWindowCrop(final boolean recoveringMemory) { + final WindowState w = mWin; + + // Need to recompute a new system decor rect each time. + if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { + // Currently can't do this cropping for scaled windows. We'll + // just keep the crop rect the same as the source surface. + w.mSystemDecorRect.set(0, 0, w.mRequestedWidth, w.mRequestedHeight); + } else if (w.mLayer >= mService.mSystemDecorLayer) { + // Above the decor layer is easy, just use the entire window. + w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), + w.mCompatFrame.height()); + } else { + final Rect decorRect = mService.mSystemDecorRect; + // Compute the offset of the window in relation to the decor rect. + final int offX = w.mXOffset + w.mFrame.left; + final int offY = w.mYOffset + w.mFrame.top; + // Initialize the decor rect to the entire frame. + w.mSystemDecorRect.set(0, 0, w.mFrame.width(), w.mFrame.height()); + // Intersect with the decor rect, offsetted by window position. + w.mSystemDecorRect.intersect(decorRect.left-offX, decorRect.top-offY, + decorRect.right-offX, decorRect.bottom-offY); + // If size compatibility is being applied to the window, the + // surface is scaled relative to the screen. Also apply this + // scaling to the crop rect. We aren't using the standard rect + // scale function because we want to round things to make the crop + // always round to a larger rect to ensure we don't crop too + // much and hide part of the window that should be seen. + if (w.mEnforceSizeCompat && w.mInvGlobalScale != 1.0f) { + final float scale = w.mInvGlobalScale; + w.mSystemDecorRect.left = (int) (w.mSystemDecorRect.left * scale - 0.5f); + w.mSystemDecorRect.top = (int) (w.mSystemDecorRect.top * scale - 0.5f); + w.mSystemDecorRect.right = (int) ((w.mSystemDecorRect.right+1) * scale - 0.5f); + w.mSystemDecorRect.bottom = (int) ((w.mSystemDecorRect.bottom+1) * scale - 0.5f); + } + } + + if (!w.mSystemDecorRect.equals(w.mLastSystemDecorRect)) { + w.mLastSystemDecorRect.set(w.mSystemDecorRect); + try { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "CROP " + w.mSystemDecorRect.toShortString(), null); + mSurface.setWindowCrop(w.mSystemDecorRect); + } catch (RuntimeException e) { + Slog.w(TAG, "Error setting crop surface of " + w + + " crop=" + w.mSystemDecorRect.toShortString(), e); + if (!recoveringMemory) { + mService.reclaimSomeSurfaceMemoryLocked(this, "crop", true); + } + } + } + } + void setSurfaceBoundaries(final boolean recoveringMemory) { final WindowState w = mWin; int width, height; @@ -1003,54 +1056,7 @@ class WindowStateAnimator { } } - // Need to recompute a new system decor rect each time. - if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { - // Currently can't do this cropping for scaled windows. We'll - // just keep the crop rect the same as the source surface. - w.mSystemDecorRect.set(0, 0, w.mRequestedWidth, w.mRequestedHeight); - } else if (w.mLayer >= mService.mSystemDecorLayer) { - // Above the decor layer is easy, just use the entire window. - w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), - w.mCompatFrame.height()); - } else { - final Rect decorRect = mService.mSystemDecorRect; - // Compute the offset of the window in relation to the decor rect. - final int offX = w.mXOffset + w.mFrame.left; - final int offY = w.mYOffset + w.mFrame.top; - // Initialize the decor rect to the entire frame. - w.mSystemDecorRect.set(0, 0, w.mFrame.width(), w.mFrame.height()); - // Intersect with the decor rect, offsetted by window position. - w.mSystemDecorRect.intersect(decorRect.left-offX, decorRect.top-offY, - decorRect.right-offX, decorRect.bottom-offY); - // If size compatibility is being applied to the window, the - // surface is scaled relative to the screen. Also apply this - // scaling to the crop rect. We aren't using the standard rect - // scale function because we want to round things to make the crop - // always round to a larger rect to ensure we don't crop too - // much and hide part of the window that should be seen. - if (w.mEnforceSizeCompat && w.mInvGlobalScale != 1.0f) { - final float scale = w.mInvGlobalScale; - w.mSystemDecorRect.left = (int) (w.mSystemDecorRect.left * scale - 0.5f); - w.mSystemDecorRect.top = (int) (w.mSystemDecorRect.top * scale - 0.5f); - w.mSystemDecorRect.right = (int) ((w.mSystemDecorRect.right+1) * scale - 0.5f); - w.mSystemDecorRect.bottom = (int) ((w.mSystemDecorRect.bottom+1) * scale - 0.5f); - } - } - - if (!w.mSystemDecorRect.equals(w.mLastSystemDecorRect)) { - w.mLastSystemDecorRect.set(w.mSystemDecorRect); - try { - if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, - "CROP " + w.mSystemDecorRect.toShortString(), null); - mSurface.setWindowCrop(w.mSystemDecorRect); - } catch (RuntimeException e) { - Slog.w(TAG, "Error setting crop surface of " + w - + " crop=" + w.mSystemDecorRect.toShortString(), e); - if (!recoveringMemory) { - mService.reclaimSomeSurfaceMemoryLocked(this, "crop", true); - } - } - } + updateSurfaceWindowCrop(recoveringMemory); } public void prepareSurfaceLocked(final boolean recoveringMemory) { @@ -1181,17 +1187,31 @@ class WindowStateAnimator { } void setWallpaperOffset(int left, int top) { + mSurfaceX = left; + mSurfaceY = top; + if (mAnimating) { + // If this window (or its app token) is animating, then the position + // of the surface will be re-computed on the next animation frame. + // We can't poke it directly here because it depends on whatever + // transformation is being applied by the animation. + return; + } + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + ">>> OPEN TRANSACTION setWallpaperOffset"); Surface.openTransaction(); try { - mSurfaceX = left; - mSurfaceY = top; - mSurface.setPosition(left, top); - mSurface.setWindowCrop(null); + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, + "POS " + left + ", " + top, null); + mSurface.setPosition(mWin.mFrame.left + left, mWin.mFrame.top + top); + updateSurfaceWindowCrop(false); } catch (RuntimeException e) { Slog.w(TAG, "Error positioning surface of " + mWin + " pos=(" + left + "," + top + ")", e); + } finally { + Surface.closeTransaction(); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + "<<< CLOSE TRANSACTION setWallpaperOffset"); } - Surface.closeTransaction(); } // This must be called while inside a transaction. diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java index 9321cb3..d0f3e62 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java @@ -72,6 +72,7 @@ public class RSTestCore { unitTests.add(new UT_clamp(this, mRes, mCtx)); unitTests.add(new UT_clamp_relaxed(this, mRes, mCtx)); unitTests.add(new UT_convert(this, mRes, mCtx)); + unitTests.add(new UT_convert_relaxed(this, mRes, mCtx)); unitTests.add(new UT_rsdebug(this, mRes, mCtx)); unitTests.add(new UT_rstime(this, mRes, mCtx)); unitTests.add(new UT_rstypes(this, mRes, mCtx)); diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert_relaxed.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert_relaxed.java new file mode 100644 index 0000000..728806c --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert_relaxed.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_convert_relaxed extends UnitTest { + private Resources mRes; + + protected UT_convert_relaxed(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "Convert (Relaxed)", ctx); + mRes = res; + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + ScriptC_convert_relaxed s = + new ScriptC_convert_relaxed(pRS, mRes, R.raw.convert_relaxed); + pRS.setMessageHandler(mRsMessage); + s.invoke_convert_test(); + pRS.finish(); + waitForMessage(); + pRS.destroy(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/convert_relaxed.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/convert_relaxed.rs new file mode 100644 index 0000000..81abb9b --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/convert_relaxed.rs @@ -0,0 +1,2 @@ +#include "convert.rs" +#pragma rs_fp_relaxed |
