diff options
Diffstat (limited to 'core/java/android')
38 files changed, 840 insertions, 276 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 5f40f25..a09607a 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -171,6 +171,11 @@ public class AccessibilityServiceInfo implements Parcelable { private boolean mCanRetrieveWindowContent; /** + * Description of the accessibility service. + */ + private String mDescription; + + /** * Creates a new instance. */ public AccessibilityServiceInfo() { @@ -240,6 +245,8 @@ public class AccessibilityServiceInfo implements Parcelable { mCanRetrieveWindowContent = asAttributes.getBoolean( com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent, false); + mDescription = asAttributes.getString( + com.android.internal.R.styleable.AccessibilityService_description); asAttributes.recycle(); } catch (NameNotFoundException e) { throw new XmlPullParserException( "Unable to create context for: " @@ -313,6 +320,18 @@ public class AccessibilityServiceInfo implements Parcelable { } /** + * Description of the accessibility service. + * <p> + * <strong>Statically set from + * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> + * </p> + * @return The description. + */ + public String getDescription() { + return mDescription; + } + + /** * {@inheritDoc} */ public int describeContents() { @@ -329,6 +348,7 @@ public class AccessibilityServiceInfo implements Parcelable { parcel.writeParcelable(mResolveInfo, 0); parcel.writeString(mSettingsActivityName); parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0); + parcel.writeString(mDescription); } private void initFromParcel(Parcel parcel) { @@ -341,6 +361,7 @@ public class AccessibilityServiceInfo implements Parcelable { mResolveInfo = parcel.readParcelable(null); mSettingsActivityName = parcel.readString(); mCanRetrieveWindowContent = (parcel.readInt() == 1); + mDescription = parcel.readString(); } @Override diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java index 12a4dbb..06d18ec 100644 --- a/core/java/android/animation/LayoutTransition.java +++ b/core/java/android/animation/LayoutTransition.java @@ -25,6 +25,7 @@ import android.view.animation.DecelerateInterpolator; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; /** @@ -178,14 +179,17 @@ public class LayoutTransition { * the transition. The reason for this is that a further layout event should cause * existing animations to stop where they are prior to starting new animations. So * we cache all of the current animations in this map for possible cancellation on - * another layout event. + * another layout event. LinkedHashMaps are used to preserve the order in which animations + * are inserted, so that we process events (such as setting up start values) in the same order. */ - private final HashMap<View, Animator> pendingAnimations = new HashMap<View, Animator>(); - private final HashMap<View, Animator> currentChangingAnimations = new HashMap<View, Animator>(); - private final HashMap<View, Animator> currentAppearingAnimations = - new HashMap<View, Animator>(); - private final HashMap<View, Animator> currentDisappearingAnimations = + private final HashMap<View, Animator> pendingAnimations = new HashMap<View, Animator>(); + private final LinkedHashMap<View, Animator> currentChangingAnimations = + new LinkedHashMap<View, Animator>(); + private final LinkedHashMap<View, Animator> currentAppearingAnimations = + new LinkedHashMap<View, Animator>(); + private final LinkedHashMap<View, Animator> currentDisappearingAnimations = + new LinkedHashMap<View, Animator>(); /** * This hashmap is used to track the listeners that have been added to the children of @@ -547,7 +551,7 @@ public class LayoutTransition { } /** - * This function sets up runs animations on all of the views that change during layout. + * This function sets up animations on all of the views that change during layout. * For every child in the parent, we create a change animation of the appropriate * type (appearing or disappearing) and ask it to populate its start values from its * target view. We add layout listeners to all child views and listen for changes. For @@ -821,24 +825,24 @@ public class LayoutTransition { */ public void cancel() { if (currentChangingAnimations.size() > 0) { - HashMap<View, Animator> currentAnimCopy = - (HashMap<View, Animator>) currentChangingAnimations.clone(); + LinkedHashMap<View, Animator> currentAnimCopy = + (LinkedHashMap<View, Animator>) currentChangingAnimations.clone(); for (Animator anim : currentAnimCopy.values()) { anim.cancel(); } currentChangingAnimations.clear(); } if (currentAppearingAnimations.size() > 0) { - HashMap<View, Animator> currentAnimCopy = - (HashMap<View, Animator>) currentAppearingAnimations.clone(); + LinkedHashMap<View, Animator> currentAnimCopy = + (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone(); for (Animator anim : currentAnimCopy.values()) { anim.end(); } currentAppearingAnimations.clear(); } if (currentDisappearingAnimations.size() > 0) { - HashMap<View, Animator> currentAnimCopy = - (HashMap<View, Animator>) currentDisappearingAnimations.clone(); + LinkedHashMap<View, Animator> currentAnimCopy = + (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone(); for (Animator anim : currentAnimCopy.values()) { anim.end(); } @@ -859,8 +863,8 @@ public class LayoutTransition { case CHANGE_APPEARING: case CHANGE_DISAPPEARING: if (currentChangingAnimations.size() > 0) { - HashMap<View, Animator> currentAnimCopy = - (HashMap<View, Animator>) currentChangingAnimations.clone(); + LinkedHashMap<View, Animator> currentAnimCopy = + (LinkedHashMap<View, Animator>) currentChangingAnimations.clone(); for (Animator anim : currentAnimCopy.values()) { anim.cancel(); } @@ -869,8 +873,8 @@ public class LayoutTransition { break; case APPEARING: if (currentAppearingAnimations.size() > 0) { - HashMap<View, Animator> currentAnimCopy = - (HashMap<View, Animator>) currentAppearingAnimations.clone(); + LinkedHashMap<View, Animator> currentAnimCopy = + (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone(); for (Animator anim : currentAnimCopy.values()) { anim.end(); } @@ -879,8 +883,8 @@ public class LayoutTransition { break; case DISAPPEARING: if (currentDisappearingAnimations.size() > 0) { - HashMap<View, Animator> currentAnimCopy = - (HashMap<View, Animator>) currentDisappearingAnimations.clone(); + LinkedHashMap<View, Animator> currentAnimCopy = + (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone(); for (Animator anim : currentAnimCopy.values()) { anim.end(); } @@ -1113,4 +1117,4 @@ public class LayoutTransition { View view, int transitionType); } -}
\ No newline at end of file +} diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index c6a746b..f6cd866 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -70,7 +70,7 @@ import android.view.HardwareRenderer; import android.view.View; import android.view.ViewDebug; import android.view.ViewManager; -import android.view.ViewAncestor; +import android.view.ViewRootImpl; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; @@ -3558,6 +3558,7 @@ public final class ActivityThread { } final void handleTrimMemory(int level) { + WindowManagerImpl.getDefault().trimMemory(level); } private final void handleBindApplication(AppBindData data) { @@ -4071,7 +4072,7 @@ public final class ActivityThread { sThreadLocal.set(this); mSystemThread = system; if (!system) { - ViewAncestor.addFirstDrawHandler(new Runnable() { + ViewRootImpl.addFirstDrawHandler(new Runnable() { public void run() { ensureJitEnabled(); } @@ -4101,7 +4102,7 @@ public final class ActivityThread { } } - ViewAncestor.addConfigCallback(new ComponentCallbacks() { + ViewRootImpl.addConfigCallback(new ComponentCallbacks() { public void onConfigurationChanged(Configuration newConfig) { synchronized (mPackages) { // We need to apply this change to the resources diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 42eda02..8e2d360 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -168,6 +168,7 @@ public class SearchDialog extends Dialog { SearchBar searchBar = (SearchBar) findViewById(com.android.internal.R.id.search_bar); searchBar.setSearchDialog(this); mSearchView = (SearchView) findViewById(com.android.internal.R.id.search_view); + mSearchView.setIconified(false); mSearchView.setOnCloseListener(mOnCloseListener); mSearchView.setOnQueryTextListener(mOnQueryChangeListener); mSearchView.setOnSuggestionListener(mOnSuggestionSelectionListener); @@ -633,31 +634,6 @@ public class SearchDialog extends Dialog { } /** - * Overrides the handling of the back key to move back to the previous - * sources or dismiss the search dialog, instead of dismissing the input - * method. - */ - @Override - public boolean dispatchKeyEventPreIme(KeyEvent event) { - if (DBG) - Log.d(LOG_TAG, "onKeyPreIme(" + event + ")"); - if (mSearchDialog != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - KeyEvent.DispatcherState state = getKeyDispatcherState(); - if (state != null) { - if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - state.startTracking(event, this); - return true; - } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled() - && state.isTracking(event)) { - mSearchDialog.onBackPressed(); - return true; - } - } - } - return super.dispatchKeyEventPreIme(event); - } - - /** * Don't allow action modes in a SearchBar, it looks silly. */ @Override diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 7fd5a7d..8472b31 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -40,7 +40,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.DisplayMetrics; import android.util.Log; -import android.view.ViewAncestor; +import android.view.ViewRootImpl; import java.io.FileOutputStream; import java.io.IOException; @@ -592,7 +592,7 @@ public class WallpaperManager { public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) { try { //Log.v(TAG, "Sending new wallpaper offsets from app..."); - ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition( + ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition( windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep); //Log.v(TAG, "...app returning after sending offsets!"); } catch (RemoteException e) { @@ -630,7 +630,7 @@ public class WallpaperManager { int x, int y, int z, Bundle extras) { try { //Log.v(TAG, "Sending new wallpaper offsets from app..."); - ViewAncestor.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand( + ViewRootImpl.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand( windowToken, action, x, y, z, extras, false); //Log.v(TAG, "...app returning after sending offsets!"); } catch (RemoteException e) { @@ -650,7 +650,7 @@ public class WallpaperManager { */ public void clearWallpaperOffsets(IBinder windowToken) { try { - ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition( + ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition( windowToken, -1, -1, -1, -1); } catch (RemoteException e) { // Ignore. diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java index a2af558..0e83dc0 100644 --- a/core/java/android/content/ContentService.java +++ b/core/java/android/content/ContentService.java @@ -20,17 +20,21 @@ import android.accounts.Account; import android.database.IContentObserver; import android.database.sqlite.SQLiteException; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import android.util.SparseIntArray; import android.Manifest; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; /** @@ -70,6 +74,40 @@ public final class ContentService extends IContentService.Stub { } else { mSyncManager.dump(fd, pw); } + pw.println(); + pw.println("Observer tree:"); + synchronized (mRootNode) { + int[] counts = new int[2]; + final SparseIntArray pidCounts = new SparseIntArray(); + mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts); + pw.println(); + ArrayList<Integer> sorted = new ArrayList<Integer>(); + for (int i=0; i<pidCounts.size(); i++) { + sorted.add(pidCounts.keyAt(i)); + } + Collections.sort(sorted, new Comparator<Integer>() { + @Override + public int compare(Integer lhs, Integer rhs) { + int lc = pidCounts.get(lhs); + int rc = pidCounts.get(rhs); + if (lc < rc) { + return 1; + } else if (lc > rc) { + return -1; + } + return 0; + } + + }); + for (int i=0; i<sorted.size(); i++) { + int pid = sorted.get(i); + pw.print(" pid "); pw.print(pid); pw.print(": "); + pw.print(pidCounts.get(pid)); pw.println(" observers"); + } + pw.println(); + pw.print(" Total number of nodes: "); pw.println(counts[0]); + pw.print(" Total number of observers: "); pw.println(counts[1]); + } } finally { restoreCallingIdentity(identityToken); } @@ -102,7 +140,8 @@ public final class ContentService extends IContentService.Stub { throw new IllegalArgumentException("You must pass a valid uri and observer"); } synchronized (mRootNode) { - mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode); + mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode, + Binder.getCallingUid(), Binder.getCallingPid()); if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri + " with notifyForDescendents " + notifyForDescendents); } @@ -465,12 +504,17 @@ public final class ContentService extends IContentService.Stub { public static final class ObserverNode { private class ObserverEntry implements IBinder.DeathRecipient { public final IContentObserver observer; + public final int uid; + public final int pid; public final boolean notifyForDescendents; private final Object observersLock; - public ObserverEntry(IContentObserver o, boolean n, Object observersLock) { + public ObserverEntry(IContentObserver o, boolean n, Object observersLock, + int _uid, int _pid) { this.observersLock = observersLock; observer = o; + uid = _uid; + pid = _pid; notifyForDescendents = n; try { observer.asBinder().linkToDeath(this, 0); @@ -484,6 +528,16 @@ public final class ContentService extends IContentService.Stub { removeObserverLocked(observer); } } + + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, + String name, String prefix, SparseIntArray pidCounts) { + pidCounts.put(pid, pidCounts.get(pid)+1); + pw.print(prefix); pw.print(name); pw.print(": pid="); + pw.print(pid); pw.print(" uid="); + pw.print(uid); pw.print(" target="); + pw.println(Integer.toHexString(System.identityHashCode( + observer != null ? observer.asBinder() : null))); + } } public static final int INSERT_TYPE = 0; @@ -498,6 +552,37 @@ public final class ContentService extends IContentService.Stub { mName = name; } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, + String name, String prefix, int[] counts, SparseIntArray pidCounts) { + String innerName = null; + if (mObservers.size() > 0) { + if ("".equals(name)) { + innerName = mName; + } else { + innerName = name + "/" + mName; + } + for (int i=0; i<mObservers.size(); i++) { + counts[1]++; + mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix, + pidCounts); + } + } + if (mChildren.size() > 0) { + if (innerName == null) { + if ("".equals(name)) { + innerName = mName; + } else { + innerName = name + "/" + mName; + } + } + for (int i=0; i<mChildren.size(); i++) { + counts[0]++; + mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix, + counts, pidCounts); + } + } + } + private String getUriSegment(Uri uri, int index) { if (uri != null) { if (index == 0) { @@ -518,15 +603,16 @@ public final class ContentService extends IContentService.Stub { } public void addObserverLocked(Uri uri, IContentObserver observer, - boolean notifyForDescendents, Object observersLock) { - addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock); + boolean notifyForDescendents, Object observersLock, int uid, int pid) { + addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock, uid, pid); } private void addObserverLocked(Uri uri, int index, IContentObserver observer, - boolean notifyForDescendents, Object observersLock) { + boolean notifyForDescendents, Object observersLock, int uid, int pid) { // If this is the leaf node add the observer if (index == countUriSegments(uri)) { - mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock)); + mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock, + uid, pid)); return; } @@ -539,7 +625,8 @@ public final class ContentService extends IContentService.Stub { for (int i = 0; i < N; i++) { ObserverNode node = mChildren.get(i); if (node.mName.equals(segment)) { - node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock); + node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, + observersLock, uid, pid); return; } } @@ -547,7 +634,8 @@ public final class ContentService extends IContentService.Stub { // No child found, create one ObserverNode node = new ObserverNode(segment); mChildren.add(node); - node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock); + node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, + observersLock, uid, pid); } public boolean removeObserverLocked(IContentObserver observer) { diff --git a/core/java/android/content/SearchRecentSuggestionsProvider.java b/core/java/android/content/SearchRecentSuggestionsProvider.java index 3d89e92..e1a8d21 100644 --- a/core/java/android/content/SearchRecentSuggestionsProvider.java +++ b/core/java/android/content/SearchRecentSuggestionsProvider.java @@ -186,6 +186,9 @@ public class SearchRecentSuggestionsProvider extends ContentProvider { mSuggestionProjection = new String [] { "0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT, + "'android.resource://system/" + + com.android.internal.R.drawable.ic_menu_recent_history + "' AS " + + SearchManager.SUGGEST_COLUMN_ICON_1, "display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, "display2 AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, "query AS " + SearchManager.SUGGEST_COLUMN_QUERY, @@ -196,6 +199,9 @@ public class SearchRecentSuggestionsProvider extends ContentProvider { mSuggestionProjection = new String [] { "0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT, + "'android.resource://system/" + + com.android.internal.R.drawable.ic_menu_recent_history + "' AS " + + SearchManager.SUGGEST_COLUMN_ICON_1, "display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, "query AS " + SearchManager.SUGGEST_COLUMN_QUERY, "_id" diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 67d200c..b548623 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -409,9 +409,10 @@ public class UsbManager { /** * Sets the current USB function. + * If function is null, then the current function is set to the default function. * - * @param function name of the USB function - * @param makeDefault true if this should be set as the default + * @param function name of the USB function, or null to restore the default function + * @param makeDefault true if the function should be set as the new default function * * {@hide} */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 23b53ae..34699e2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2683,6 +2683,13 @@ public final class Settings { public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled"; /** + * If touch exploration is requested. Touch exploration is enabled if it is + * requested by this setting, accessibility is enabled and there is at least + * one enabled accessibility serivce that provides spoken feedback. + */ + public static final String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested"; + + /** * List of the enabled accessibility providers. */ public static final String ENABLED_ACCESSIBILITY_SERVICES = diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 8fc8b9d..c51ba2a 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -51,7 +51,7 @@ import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; -import android.view.ViewAncestor; +import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; @@ -650,7 +650,7 @@ public abstract class WallpaperService extends Service { mWindowToken = wrapper.mWindowToken; mSurfaceHolder.setSizeFromLayout(); mInitializing = true; - mSession = ViewAncestor.getWindowSession(getMainLooper()); + mSession = ViewRootImpl.getWindowSession(getMainLooper()); mWindow.setSession(mSession); diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java new file mode 100644 index 0000000..70dc9aa --- /dev/null +++ b/core/java/android/util/Config.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +/** + * @deprecated This class is not useful, it just returns the same value for + * all constants, and has always done this. Do not use it. + */ +@Deprecated +public final class Config { + /** @hide */ public Config() {} + + /** + * @deprecated Always false. + */ + @Deprecated + public static final boolean DEBUG = false; + + /** + * @deprecated Always true. + */ + @Deprecated + public static final boolean RELEASE = true; + + /** + * @deprecated Always false. + */ + @Deprecated + public static final boolean PROFILE = false; + + /** + * @deprecated Always false. + */ + @Deprecated + public static final boolean LOGV = false; + + /** + * @deprecated Always true. + */ + @Deprecated + public static final boolean LOGD = true; +} diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java index 132b595..09ce8e4 100644 --- a/core/java/android/util/JsonReader.java +++ b/core/java/android/util/JsonReader.java @@ -196,6 +196,12 @@ public final class JsonReader implements Closeable { private int pos = 0; private int limit = 0; + /* + * The offset of the first character in the buffer. + */ + private int bufferStartLine = 1; + private int bufferStartColumn = 1; + private final List<JsonScope> stack = new ArrayList<JsonScope>(); { push(JsonScope.EMPTY_DOCUMENT); @@ -711,6 +717,16 @@ public final class JsonReader implements Closeable { * false. */ private boolean fillBuffer(int minimum) throws IOException { + // Before clobbering the old characters, update where buffer starts + for (int i = 0; i < pos; i++) { + if (buffer[i] == '\n') { + bufferStartLine++; + bufferStartColumn = 1; + } else { + bufferStartColumn++; + } + } + if (limit != pos) { limit -= pos; System.arraycopy(buffer, pos, buffer, 0, limit); @@ -729,6 +745,28 @@ public final class JsonReader implements Closeable { return false; } + private int getLineNumber() { + int result = bufferStartLine; + for (int i = 0; i < pos; i++) { + if (buffer[i] == '\n') { + result++; + } + } + return result; + } + + private int getColumnNumber() { + int result = bufferStartColumn; + for (int i = 0; i < pos; i++) { + if (buffer[i] == '\n') { + result = 1; + } else { + result++; + } + } + return result; + } + private int nextNonWhitespace() throws IOException { while (pos < limit || fillBuffer(1)) { int c = buffer[pos++]; @@ -1107,7 +1145,8 @@ public final class JsonReader implements Closeable { * with this reader's content. */ private IOException syntaxError(String message) throws IOException { - throw new MalformedJsonException(message + " near " + getSnippet()); + throw new MalformedJsonException(message + + " at line " + getLineNumber() + " column " + getColumnNumber()); } private CharSequence getSnippet() { diff --git a/core/java/android/util/JsonWriter.java b/core/java/android/util/JsonWriter.java index 47e84c5..c1e6e40 100644 --- a/core/java/android/util/JsonWriter.java +++ b/core/java/android/util/JsonWriter.java @@ -407,6 +407,11 @@ public final class JsonWriter implements Closeable { * quotation marks except for the characters that must be escaped: * quotation mark, reverse solidus, and the control characters * (U+0000 through U+001F)." + * + * We also escape '\u2028' and '\u2029', which JavaScript interprets + * as newline characters. This prevents eval() from failing with a + * syntax error. + * http://code.google.com/p/google-gson/issues/detail?id=341 */ switch (c) { case '"': @@ -435,6 +440,11 @@ public final class JsonWriter implements Closeable { out.write("\\f"); break; + case '\u2028': + case '\u2029': + out.write(String.format("\\u%04x", (int) c)); + break; + default: if (c <= 0x1F) { out.write(String.format("\\u%04x", (int) c)); diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 7fc43b9..7cf4579 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -23,10 +23,14 @@ import com.android.internal.util.ArrayUtils; * there can be gaps in the indices. It is intended to be more efficient * than using a HashMap to map Integers to Objects. */ -public class SparseArray<E> { +public class SparseArray<E> implements Cloneable { private static final Object DELETED = new Object(); private boolean mGarbage = false; + private int[] mKeys; + private Object[] mValues; + private int mSize; + /** * Creates a new SparseArray containing no mappings. */ @@ -47,6 +51,20 @@ public class SparseArray<E> { mSize = 0; } + @Override + @SuppressWarnings("unchecked") + public SparseArray<E> clone() { + SparseArray<E> clone = null; + try { + clone = (SparseArray<E>) super.clone(); + clone.mKeys = mKeys.clone(); + clone.mValues = mValues.clone(); + } catch (CloneNotSupportedException cnse) { + /* ignore */ + } + return clone; + } + /** * Gets the Object mapped from the specified key, or <code>null</code> * if no such mapping has been made. @@ -59,6 +77,7 @@ public class SparseArray<E> { * Gets the Object mapped from the specified key, or the specified Object * if no such mapping has been made. */ + @SuppressWarnings("unchecked") public E get(int key, E valueIfKeyNotFound) { int i = binarySearch(mKeys, 0, mSize, key); @@ -209,6 +228,7 @@ public class SparseArray<E> { * the value from the <code>index</code>th key-value mapping that this * SparseArray stores. */ + @SuppressWarnings("unchecked") public E valueAt(int index) { if (mGarbage) { gc(); @@ -331,20 +351,4 @@ public class SparseArray<E> { else return ~high; } - - private void checkIntegrity() { - for (int i = 1; i < mSize; i++) { - if (mKeys[i] <= mKeys[i - 1]) { - for (int j = 0; j < mSize; j++) { - Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]); - } - - throw new RuntimeException(); - } - } - } - - private int[] mKeys; - private Object[] mValues; - private int mSize; } diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java index f7799de..76c47c6 100644 --- a/core/java/android/util/SparseBooleanArray.java +++ b/core/java/android/util/SparseBooleanArray.java @@ -24,7 +24,7 @@ import com.android.internal.util.ArrayUtils; * there can be gaps in the indices. It is intended to be more efficient * than using a HashMap to map Integers to Booleans. */ -public class SparseBooleanArray { +public class SparseBooleanArray implements Cloneable { /** * Creates a new SparseBooleanArray containing no mappings. */ @@ -45,6 +45,19 @@ public class SparseBooleanArray { mSize = 0; } + @Override + public SparseBooleanArray clone() { + SparseBooleanArray clone = null; + try { + clone = (SparseBooleanArray) super.clone(); + clone.mKeys = mKeys.clone(); + clone.mValues = mValues.clone(); + } catch (CloneNotSupportedException cnse) { + /* ignore */ + } + return clone; + } + /** * Gets the boolean mapped from the specified key, or <code>false</code> * if no such mapping has been made. @@ -227,18 +240,6 @@ public class SparseBooleanArray { return ~high; } - private void checkIntegrity() { - for (int i = 1; i < mSize; i++) { - if (mKeys[i] <= mKeys[i - 1]) { - for (int j = 0; j < mSize; j++) { - Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]); - } - - throw new RuntimeException(); - } - } - } - private int[] mKeys; private boolean[] mValues; private int mSize; diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index 9ab3b53..8d11177 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -23,7 +23,12 @@ import com.android.internal.util.ArrayUtils; * there can be gaps in the indices. It is intended to be more efficient * than using a HashMap to map Integers to Integers. */ -public class SparseIntArray { +public class SparseIntArray implements Cloneable { + + private int[] mKeys; + private int[] mValues; + private int mSize; + /** * Creates a new SparseIntArray containing no mappings. */ @@ -44,6 +49,19 @@ public class SparseIntArray { mSize = 0; } + @Override + public SparseIntArray clone() { + SparseIntArray clone = null; + try { + clone = (SparseIntArray) super.clone(); + clone.mKeys = mKeys.clone(); + clone.mValues = mValues.clone(); + } catch (CloneNotSupportedException cnse) { + /* ignore */ + } + return clone; + } + /** * Gets the int mapped from the specified key, or <code>0</code> * if no such mapping has been made. @@ -232,20 +250,4 @@ public class SparseIntArray { else return ~high; } - - private void checkIntegrity() { - for (int i = 1; i < mSize; i++) { - if (mKeys[i] <= mKeys[i - 1]) { - for (int j = 0; j < mSize; j++) { - Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]); - } - - throw new RuntimeException(); - } - } - } - - private int[] mKeys; - private int[] mValues; - private int mSize; } diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java index bfafa98..e954983 100644 --- a/core/java/android/view/ActionMode.java +++ b/core/java/android/view/ActionMode.java @@ -23,6 +23,36 @@ package android.view; * Examples of good action modes include selection modes, search, content editing, etc. */ public abstract class ActionMode { + private Object mTag; + + /** + * Set a tag object associated with this ActionMode. + * + * <p>Like the tag available to views, this allows applications to associate arbitrary + * data with an ActionMode for later reference. + * + * @param tag Tag to associate with this ActionMode + * + * @see #getTag() + */ + public void setTag(Object tag) { + mTag = tag; + } + + /** + * Retrieve the tag object associated with this ActionMode. + * + * <p>Like the tag available to views, this allows applications to associate arbitrary + * data with an ActionMode for later reference. + * + * @return Tag associated with this ActionMode + * + * @see #setTag(Object) + */ + public Object getTag() { + return mTag; + } + /** * Set the title of the action mode. This method will have no visible effect if * a custom view has been set. diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 4987e2f..80244bb 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -286,6 +286,38 @@ class GLES20Canvas extends HardwareCanvas { private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction); + + /////////////////////////////////////////////////////////////////////////// + // Memory + /////////////////////////////////////////////////////////////////////////// + + /** + * @see #flushCaches(int) + */ + public static final int FLUSH_CACHES_MODERATE = 0; + + /** + * @see #flushCaches(int) + */ + public static final int FLUSH_CACHES_FULL = 1; + + /** + * Flush caches to reclaim as much memory as possible. The amount of memory + * to reclaim is indicate by the level parameter. + * + * The level can be one of {@link #FLUSH_CACHES_MODERATE} or + * {@link #FLUSH_CACHES_FULL}. + * + * @param level Hint about the amount of memory to reclaim + * + * @hide + */ + public static void flushCaches(int level) { + nFlushCaches(level); + } + + private static native void nFlushCaches(int level); + /////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 011e44c..9a2564f 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -17,6 +17,7 @@ package android.view; +import android.content.ComponentCallbacks; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.SurfaceTexture; @@ -263,6 +264,18 @@ public abstract class HardwareRenderer { } /** + * Invoke this method when the system is running out of memory. This + * method will attempt to recover as much memory as possible, based on + * the specified hint. + * + * @param level Hint about the amount of memory that should be trimmed, + * see {@link android.content.ComponentCallbacks} + */ + static void trimMemory(int level) { + Gl20Renderer.flushCaches(level); + } + + /** * Indicates whether hardware acceleration is currently enabled. * * @return True if hardware acceleration is in use, false otherwise. @@ -858,5 +871,16 @@ public abstract class HardwareRenderer { } return null; } + + static void flushCaches(int level) { + switch (level) { + case ComponentCallbacks.TRIM_MEMORY_MODERATE: + GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE); + break; + case ComponentCallbacks.TRIM_MEMORY_COMPLETE: + GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL); + break; + } + } } } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 764899f..cbdb38e 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -426,7 +426,7 @@ public class SurfaceView extends View { if (!mHaveFrame) { return; } - ViewAncestor viewRoot = (ViewAncestor) getRootView().getParent(); + ViewRootImpl viewRoot = (ViewRootImpl) getRootView().getParent(); if (viewRoot != null) { mTranslator = viewRoot.mTranslator; } diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index d656f31..96d6f09 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.util.AttributeSet; import android.util.Log; @@ -107,6 +108,14 @@ public class TextureView extends View { private SurfaceTexture.OnFrameAvailableListener mUpdateListener; + private Canvas mCanvas; + private int mSaveCount; + + private final Object[] mNativeWindowLock = new Object[0]; + // Used from native code, do not write! + @SuppressWarnings({"UnusedDeclaration"}) + private int mNativeWindow; + /** * Creates a new TextureView. * @@ -190,7 +199,11 @@ public class TextureView extends View { mListener.onSurfaceTextureDestroyed(mSurface); } - mLayer.destroy(); + synchronized (mNativeWindowLock) { + nDestroyNativeWindow(); + } + + mLayer.destroy(); mSurface = null; mLayer = null; } @@ -274,6 +287,7 @@ public class TextureView extends View { mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque); mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer); nSetDefaultBufferSize(mSurface, getWidth(), getHeight()); + nCreateNativeWindow(mSurface); mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() { @Override @@ -431,6 +445,79 @@ public class TextureView extends View { } /** + * <p>Start editing the pixels in the surface. The returned Canvas can be used + * to draw into the surface's bitmap. A null is returned if the surface has + * not been created or otherwise cannot be edited. You will usually need + * to implement + * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)} + * to find out when the Surface is available for use.</p> + * + * <p>The content of the Surface is never preserved between unlockCanvas() + * and lockCanvas(), for this reason, every pixel within the Surface area + * must be written. The only exception to this rule is when a dirty + * rectangle is specified, in which case, non-dirty pixels will be + * preserved.</p> + * + * @return A Canvas used to draw into the surface. + * + * @see #lockCanvas(android.graphics.Rect) + * @see #unlockCanvasAndPost(android.graphics.Canvas) + */ + public Canvas lockCanvas() { + return lockCanvas(null); + } + + /** + * Just like {@link #lockCanvas()} but allows specification of a dirty + * rectangle. Every pixel within that rectangle must be written; however + * pixels outside the dirty rectangle will be preserved by the next call + * to lockCanvas(). + * + * @param dirty Area of the surface that will be modified. + + * @return A Canvas used to draw into the surface. + * + * @see #lockCanvas() + * @see #unlockCanvasAndPost(android.graphics.Canvas) + */ + public Canvas lockCanvas(Rect dirty) { + if (!isAvailable()) return null; + + if (mCanvas == null) { + mCanvas = new Canvas(); + } + + synchronized (mNativeWindowLock) { + nLockCanvas(mNativeWindow, mCanvas, dirty); + } + mSaveCount = mCanvas.save(); + + return mCanvas; + } + + /** + * Finish editing pixels in the surface. After this call, the surface's + * current pixels will be shown on the screen, but its content is lost, + * in particular there is no guarantee that the content of the Surface + * will remain unchanged when lockCanvas() is called again. + * + * @param canvas The Canvas previously returned by lockCanvas() + * + * @see #lockCanvas() + * @see #lockCanvas(android.graphics.Rect) + */ + public void unlockCanvasAndPost(Canvas canvas) { + if (mCanvas != null && canvas == mCanvas) { + canvas.restoreToCount(mSaveCount); + mSaveCount = 0; + + synchronized (mNativeWindowLock) { + nUnlockCanvasAndPost(mNativeWindow, mCanvas); + } + } + } + + /** * Returns the {@link SurfaceTexture} used by this view. This method * may return null if the view is not attached to a window or if the surface * texture has not been initialized yet. @@ -506,6 +593,12 @@ public class TextureView extends View { public void onSurfaceTextureUpdated(SurfaceTexture surface); } + private native void nCreateNativeWindow(SurfaceTexture surface); + private native void nDestroyNativeWindow(); + private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture, int width, int height); + + private static native void nLockCanvas(int nativeWindow, Canvas canvas, Rect dirty); + private static native void nUnlockCanvasAndPost(int nativeWindow, Canvas canvas); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 41b9e2d..4e9c0b7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5043,9 +5043,9 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit } /** Gets the ViewAncestor, or null if not attached. */ - /*package*/ ViewAncestor getViewAncestor() { + /*package*/ ViewRootImpl getViewRootImpl() { View root = getRootView(); - return root != null ? (ViewAncestor)root.getParent() : null; + return root != null ? (ViewRootImpl)root.getParent() : null; } /** @@ -5061,7 +5061,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit public final boolean requestFocusFromTouch() { // Leave touch mode if we need to if (isInTouchMode()) { - ViewAncestor viewRoot = getViewAncestor(); + ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null) { viewRoot.ensureTouchMode(false); } @@ -5653,7 +5653,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit if (mAttachInfo != null) { return mAttachInfo.mInTouchMode; } else { - return ViewAncestor.isInTouchMode(); + return ViewRootImpl.isInTouchMode(); } } @@ -8254,7 +8254,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit handler = attachInfo.mHandler; } else { // Assume that post will succeed later - ViewAncestor.getRunQueue().post(action); + ViewRootImpl.getRunQueue().post(action); return true; } @@ -8284,7 +8284,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit handler = attachInfo.mHandler; } else { // Assume that post will succeed later - ViewAncestor.getRunQueue().postDelayed(action, delayMillis); + ViewRootImpl.getRunQueue().postDelayed(action, delayMillis); return true; } @@ -8308,7 +8308,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit handler = attachInfo.mHandler; } else { // Assume that post will succeed later - ViewAncestor.getRunQueue().removeCallbacks(action); + ViewRootImpl.getRunQueue().removeCallbacks(action); return true; } @@ -9127,12 +9127,12 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit // Start user padding override Left user padding. Otherwise, if Left user // padding is not defined, use the default left padding. If Left user padding // is defined, just use it. - if (mUserPaddingStart > 0) { + if (mUserPaddingStart >= 0) { mUserPaddingLeft = mUserPaddingStart; } else if (mUserPaddingLeft < 0) { mUserPaddingLeft = mPaddingLeft; } - if (mUserPaddingEnd > 0) { + if (mUserPaddingEnd >= 0) { mUserPaddingRight = mUserPaddingEnd; } else if (mUserPaddingRight < 0) { mUserPaddingRight = mPaddingRight; @@ -11580,9 +11580,9 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit viewParent = view.mParent; } - if (viewParent instanceof ViewAncestor) { + if (viewParent instanceof ViewRootImpl) { // *cough* - final ViewAncestor vr = (ViewAncestor)viewParent; + final ViewRootImpl vr = (ViewRootImpl)viewParent; location[1] -= vr.mCurScrollY; } } @@ -12709,7 +12709,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit surface.unlockCanvasAndPost(canvas); } - final ViewAncestor root = getViewAncestor(); + final ViewRootImpl root = getViewRootImpl(); // Cache the local state object for delivery with DragEvents root.setLocalDragState(myLocalState); @@ -13916,7 +13916,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit Canvas mCanvas; /** - * A Handler supplied by a view's {@link android.view.ViewAncestor}. This + * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This * handler can be used to pump events in the UI events queue. */ final Handler mHandler; diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index f7f5a21..b85159b 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -366,7 +366,7 @@ public class ViewDebug { } private static BufferedWriter sHierarchyTraces; - private static ViewAncestor sHierarhcyRoot; + private static ViewRootImpl sHierarhcyRoot; private static String sHierarchyTracePrefix; /** @@ -415,7 +415,7 @@ public class ViewDebug { * @hide */ public static long getViewAncestorInstanceCount() { - return Debug.countInstancesOfClass(ViewAncestor.class); + return Debug.countInstancesOfClass(ViewRootImpl.class); } /** @@ -748,7 +748,7 @@ public class ViewDebug { return; } - sHierarhcyRoot = (ViewAncestor) view.getRootView().getParent(); + sHierarhcyRoot = (ViewRootImpl) view.getRootView().getParent(); } /** @@ -1100,7 +1100,7 @@ public class ViewDebug { private static void outputDisplayList(View root, String parameter) throws IOException { final View view = findView(root, parameter); - view.getViewAncestor().outputDisplayList(view); + view.getViewRootImpl().outputDisplayList(view); } private static void capture(View root, final OutputStream clientStream, String parameter) diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index cb3e9c6..5f7673a 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -954,7 +954,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final float tx = event.mX; final float ty = event.mY; - ViewAncestor root = getViewAncestor(); + ViewRootImpl root = getViewRootImpl(); // Dispatch down the view hierarchy switch (event.mAction) { @@ -3839,13 +3839,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (drawAnimation) { if (view != null) { view.mPrivateFlags |= DRAW_ANIMATION; - } else if (parent instanceof ViewAncestor) { - ((ViewAncestor) parent).mIsAnimating = true; + } else if (parent instanceof ViewRootImpl) { + ((ViewRootImpl) parent).mIsAnimating = true; } } - if (parent instanceof ViewAncestor) { - ((ViewAncestor) parent).invalidate(); + if (parent instanceof ViewRootImpl) { + ((ViewRootImpl) parent).invalidate(); parent = null; } else if (view != null) { if ((view.mPrivateFlags & DRAWN) == DRAWN || @@ -3902,8 +3902,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (drawAnimation) { if (view != null) { view.mPrivateFlags |= DRAW_ANIMATION; - } else if (parent instanceof ViewAncestor) { - ((ViewAncestor) parent).mIsAnimating = true; + } else if (parent instanceof ViewRootImpl) { + ((ViewRootImpl) parent).mIsAnimating = true; } } @@ -4426,7 +4426,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // If this group is dirty, check that the parent is dirty as well if ((mPrivateFlags & DIRTY_MASK) != 0) { final ViewParent parent = getParent(); - if (parent != null && !(parent instanceof ViewAncestor)) { + if (parent != null && !(parent instanceof ViewRootImpl)) { if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) { result = false; android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, @@ -4995,7 +4995,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @hide */ public void requestTransitionStart(LayoutTransition transition) { - ViewAncestor viewAncestor = getViewAncestor(); + ViewRootImpl viewAncestor = getViewRootImpl(); viewAncestor.requestTransitionStart(transition); } diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewRootImpl.java index ac73611..470493d 100644 --- a/core/java/android/view/ViewAncestor.java +++ b/core/java/android/view/ViewRootImpl.java @@ -92,7 +92,7 @@ import java.util.List; * {@hide} */ @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) -public final class ViewAncestor extends Handler implements ViewParent, +public final class ViewRootImpl extends Handler implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { private static final String TAG = "ViewAncestor"; private static final boolean DBG = false; @@ -303,7 +303,7 @@ public final class ViewAncestor extends Handler implements ViewParent, } } - public ViewAncestor(Context context) { + public ViewRootImpl(Context context) { super(); if (MEASURE_LATENCY) { @@ -3807,14 +3807,14 @@ public final class ViewAncestor extends Handler implements ViewParent, } static class InputMethodCallback extends IInputMethodCallback.Stub { - private WeakReference<ViewAncestor> mViewAncestor; + private WeakReference<ViewRootImpl> mViewAncestor; - public InputMethodCallback(ViewAncestor viewAncestor) { - mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor); + public InputMethodCallback(ViewRootImpl viewAncestor) { + mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); } public void finishedEvent(int seq, boolean handled) { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchFinishedEvent(seq, handled); } @@ -3826,15 +3826,15 @@ public final class ViewAncestor extends Handler implements ViewParent, } static class W extends IWindow.Stub { - private final WeakReference<ViewAncestor> mViewAncestor; + private final WeakReference<ViewRootImpl> mViewAncestor; - W(ViewAncestor viewAncestor) { - mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor); + W(ViewRootImpl viewAncestor) { + mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); } public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets, boolean reportDraw, Configuration newConfig) { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig); @@ -3842,21 +3842,21 @@ public final class ViewAncestor extends Handler implements ViewParent, } public void dispatchAppVisibility(boolean visible) { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchAppVisibility(visible); } } public void dispatchGetNewSurface() { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchGetNewSurface(); } } public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.windowFocusChanged(hasFocus, inTouchMode); } @@ -3872,7 +3872,7 @@ public final class ViewAncestor extends Handler implements ViewParent, } public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { final View view = viewAncestor.mView; if (view != null) { @@ -3903,7 +3903,7 @@ public final class ViewAncestor extends Handler implements ViewParent, } public void closeSystemDialogs(String reason) { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchCloseSystemDialogs(reason); } @@ -3931,14 +3931,14 @@ public final class ViewAncestor extends Handler implements ViewParent, /* Drag/drop */ public void dispatchDragEvent(DragEvent event) { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchDragEvent(event); } } public void dispatchSystemUiVisibilityChanged(int visibility) { - final ViewAncestor viewAncestor = mViewAncestor.get(); + final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchSystemUiVisibilityChanged(visibility); } @@ -4269,7 +4269,7 @@ public final class ViewAncestor extends Handler implements ViewParent, if (!registered) { mAttachInfo.mAccessibilityWindowId = mAccessibilityManager.addAccessibilityInteractionConnection(mWindow, - new AccessibilityInteractionConnection(ViewAncestor.this)); + new AccessibilityInteractionConnection(ViewRootImpl.this)); } } @@ -4289,10 +4289,10 @@ public final class ViewAncestor extends Handler implements ViewParent, */ final class AccessibilityInteractionConnection extends IAccessibilityInteractionConnection.Stub { - private final WeakReference<ViewAncestor> mViewAncestor; + private final WeakReference<ViewRootImpl> mViewAncestor; - AccessibilityInteractionConnection(ViewAncestor viewAncestor) { - mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor); + AccessibilityInteractionConnection(ViewRootImpl viewAncestor) { + mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); } public void findAccessibilityNodeInfoByAccessibilityId(int accessibilityId, @@ -4421,7 +4421,7 @@ public final class ViewAncestor extends Handler implements ViewParent, try { FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate; predicate.init(accessibilityId); - View root = ViewAncestor.this.mView; + View root = ViewRootImpl.this.mView; View target = root.findViewByPredicate(predicate); if (target != null && target.isShown()) { info = target.createAccessibilityNodeInfo(); @@ -4453,7 +4453,7 @@ public final class ViewAncestor extends Handler implements ViewParent, AccessibilityNodeInfo info = null; try { - View root = ViewAncestor.this.mView; + View root = ViewRootImpl.this.mView; View target = root.findViewById(viewId); if (target != null && target.isShown()) { info = target.createAccessibilityNodeInfo(); @@ -4499,7 +4499,7 @@ public final class ViewAncestor extends Handler implements ViewParent, if (accessibilityViewId != View.NO_ID) { root = findViewByAccessibilityId(accessibilityViewId); } else { - root = ViewAncestor.this.mView; + root = ViewRootImpl.this.mView; } if (root == null || !root.isShown()) { @@ -4624,7 +4624,7 @@ public final class ViewAncestor extends Handler implements ViewParent, } private View findViewByAccessibilityId(int accessibilityId) { - View root = ViewAncestor.this.mView; + View root = ViewRootImpl.this.mView; if (root == null) { return null; } diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 54e7c04..a451bb5 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -16,18 +16,16 @@ package android.view; -import java.util.HashMap; - import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.IBinder; import android.util.AndroidRuntimeException; import android.util.Log; -import android.util.Slog; -import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; +import java.util.HashMap; + final class WindowLeaked extends AndroidRuntimeException { public WindowLeaked(String msg) { super(msg); @@ -80,7 +78,7 @@ public class WindowManagerImpl implements WindowManager { public static final int ADD_PERMISSION_DENIED = -8; private View[] mViews; - private ViewAncestor[] mRoots; + private ViewRootImpl[] mRoots; private WindowManager.LayoutParams[] mParams; private final static Object sLock = new Object(); @@ -204,7 +202,7 @@ public class WindowManagerImpl implements WindowManager { final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; - ViewAncestor root; + ViewRootImpl root; View panelParentView = null; synchronized (this) { @@ -241,7 +239,7 @@ public class WindowManagerImpl implements WindowManager { } } - root = new ViewAncestor(view.getContext()); + root = new ViewRootImpl(view.getContext()); root.mAddNesting = 1; if (cih == null) { root.mCompatibilityInfo = new CompatibilityInfoHolder(); @@ -254,7 +252,7 @@ public class WindowManagerImpl implements WindowManager { if (mViews == null) { index = 1; mViews = new View[1]; - mRoots = new ViewAncestor[1]; + mRoots = new ViewRootImpl[1]; mParams = new WindowManager.LayoutParams[1]; } else { index = mViews.length + 1; @@ -262,7 +260,7 @@ public class WindowManagerImpl implements WindowManager { mViews = new View[index]; System.arraycopy(old, 0, mViews, 0, index-1); old = mRoots; - mRoots = new ViewAncestor[index]; + mRoots = new ViewRootImpl[index]; System.arraycopy(old, 0, mRoots, 0, index-1); old = mParams; mParams = new WindowManager.LayoutParams[index]; @@ -290,7 +288,7 @@ public class WindowManagerImpl implements WindowManager { synchronized (this) { int index = findViewLocked(view, true); - ViewAncestor root = mRoots[index]; + ViewRootImpl root = mRoots[index]; mParams[index] = wparams; root.setLayoutParams(wparams, false); } @@ -312,7 +310,7 @@ public class WindowManagerImpl implements WindowManager { public void removeViewImmediate(View view) { synchronized (this) { int index = findViewLocked(view, true); - ViewAncestor root = mRoots[index]; + ViewRootImpl root = mRoots[index]; View curView = root.getView(); root.mAddNesting = 0; @@ -328,7 +326,7 @@ public class WindowManagerImpl implements WindowManager { } View removeViewLocked(int index) { - ViewAncestor root = mRoots[index]; + ViewRootImpl root = mRoots[index]; View view = root.getView(); // Don't really remove until we have matched all calls to add(). @@ -356,7 +354,7 @@ public class WindowManagerImpl implements WindowManager { removeItem(tmpViews, mViews, index); mViews = tmpViews; - ViewAncestor[] tmpRoots = new ViewAncestor[count-1]; + ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1]; removeItem(tmpRoots, mRoots, index); mRoots = tmpRoots; @@ -383,7 +381,7 @@ public class WindowManagerImpl implements WindowManager { //Log.i("foo", "@ " + i + " token " + mParams[i].token // + " view " + mRoots[i].getView()); if (token == null || mParams[i].token == token) { - ViewAncestor root = mRoots[i]; + ViewRootImpl root = mRoots[i]; root.mAddNesting = 1; //Log.i("foo", "Force closing " + root); @@ -402,7 +400,16 @@ public class WindowManagerImpl implements WindowManager { } } } - + + /** + * @param level See {@link android.content.ComponentCallbacks} + */ + public void trimMemory(int level) { + if (HardwareRenderer.isAvailable()) { + HardwareRenderer.trimMemory(level); + } + } + public void setStoppedState(IBinder token, boolean stopped) { synchronized (this) { if (mViews == null) @@ -410,7 +417,7 @@ public class WindowManagerImpl implements WindowManager { int count = mViews.length; for (int i=0; i<count; i++) { if (token == null || mParams[i].token == token) { - ViewAncestor root = mRoots[i]; + ViewRootImpl root = mRoots[i]; root.setStopped(stopped); } } @@ -422,7 +429,7 @@ public class WindowManagerImpl implements WindowManager { int count = mViews.length; config = new Configuration(config); for (int i=0; i<count; i++) { - ViewAncestor root = mRoots[i]; + ViewRootImpl root = mRoots[i]; root.requestUpdateConfiguration(config); } } @@ -430,13 +437,13 @@ public class WindowManagerImpl implements WindowManager { public WindowManager.LayoutParams getRootViewLayoutParameter(View view) { ViewParent vp = view.getParent(); - while (vp != null && !(vp instanceof ViewAncestor)) { + while (vp != null && !(vp instanceof ViewRootImpl)) { vp = vp.getParent(); } if (vp == null) return null; - ViewAncestor vr = (ViewAncestor)vp; + ViewRootImpl vr = (ViewRootImpl)vp; int N = mRoots.length; for (int i = 0; i < N; ++i) { @@ -456,8 +463,7 @@ public class WindowManagerImpl implements WindowManager { return new Display(Display.DEFAULT_DISPLAY, null); } - private static void removeItem(Object[] dst, Object[] src, int index) - { + private static void removeItem(Object[] dst, Object[] src, int index) { if (dst.length > 0) { if (index > 0) { System.arraycopy(src, 0, dst, 0, index); @@ -468,8 +474,7 @@ public class WindowManagerImpl implements WindowManager { } } - private int findViewLocked(View view, boolean required) - { + private int findViewLocked(View view, boolean required) { synchronized (this) { final int count = mViews != null ? mViews.length : 0; for (int i=0; i<count; i++) { diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index ac86769..9be2a67 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -552,7 +552,8 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par /** * Returns a cached instance if such is available or a new one is - * initialized with from the given <code>event</code>. + * created. The returned instance is initialized from the given + * <code>event</code>. * * @param event The other event. * @return An instance. diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 314b7ca..83c73cb 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -71,7 +71,9 @@ public final class AccessibilityManager { private static AccessibilityManager sInstance; - private static final int DO_SET_ENABLED = 10; + private static final int DO_SET_ACCESSIBILITY_ENABLED = 10; + + private static final int DO_SET_TOUCH_EXPLORATION_ENABLED = 20; final IAccessibilityManager mService; @@ -79,6 +81,8 @@ public final class AccessibilityManager { boolean mIsEnabled; + boolean mIsTouchExplorationEnabled; + final CopyOnWriteArrayList<AccessibilityStateChangeListener> mAccessibilityStateChangeListeners = new CopyOnWriteArrayList<AccessibilityStateChangeListener>(); @@ -97,7 +101,12 @@ public final class AccessibilityManager { final IAccessibilityManagerClient.Stub mClient = new IAccessibilityManagerClient.Stub() { public void setEnabled(boolean enabled) { - mHandler.obtainMessage(DO_SET_ENABLED, enabled ? 1 : 0, 0).sendToTarget(); + mHandler.obtainMessage(DO_SET_ACCESSIBILITY_ENABLED, enabled ? 1 : 0, 0).sendToTarget(); + } + + public void setTouchExplorationEnabled(boolean enabled) { + mHandler.obtainMessage(DO_SET_TOUCH_EXPLORATION_ENABLED, + enabled ? 1 : 0, 0).sendToTarget(); } }; @@ -110,9 +119,14 @@ public final class AccessibilityManager { @Override public void handleMessage(Message message) { switch (message.what) { - case DO_SET_ENABLED : - final boolean isEnabled = (message.arg1 == 1); - setAccessibilityState(isEnabled); + case DO_SET_ACCESSIBILITY_ENABLED : + final boolean isAccessibilityEnabled = (message.arg1 == 1); + setAccessibilityState(isAccessibilityEnabled); + return; + case DO_SET_TOUCH_EXPLORATION_ENABLED : + synchronized (mHandler) { + mIsTouchExplorationEnabled = (message.arg1 == 1); + } return; default : Log.w(LOG_TAG, "Unknown message type: " + message.what); @@ -168,6 +182,17 @@ public final class AccessibilityManager { } /** + * Returns if the touch exploration in the system is enabled. + * + * @return True if touch exploration is enabled, false otherwise. + */ + public boolean isTouchExplorationEnabled() { + synchronized (mHandler) { + return mIsTouchExplorationEnabled; + } + } + + /** * Returns the client interface this instance registers in * the centralized accessibility manager service. * diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 031c6ae..0e04471 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -120,7 +120,7 @@ public class AccessibilityNodeInfo implements Parcelable { private CharSequence mText; private CharSequence mContentDescription; - private final SparseIntArray mChildAccessibilityIds = new SparseIntArray(); + private SparseIntArray mChildAccessibilityIds = new SparseIntArray(); private int mActions; private IAccessibilityServiceConnection mConnection; @@ -873,6 +873,20 @@ public class AccessibilityNodeInfo implements Parcelable { } /** + * Returns a cached instance if such is available or a new one is + * create. The returned instance is initialized from the given + * <code>info</code>. + * + * @param info The other info. + * @return An instance. + */ + public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) { + AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain(); + infoClone.init(info); + return infoClone; + } + + /** * Return an instance back to be reused. * <p> * <strong>Note:</strong> You must not touch the object after calling this function. @@ -945,6 +959,28 @@ public class AccessibilityNodeInfo implements Parcelable { } /** + * Initializes this instance from another one. + * + * @param other The other instance. + */ + private void init(AccessibilityNodeInfo other) { + mSealed = other.mSealed; + mConnection = other.mConnection; + mAccessibilityViewId = other.mAccessibilityViewId; + mParentAccessibilityViewId = other.mParentAccessibilityViewId; + mAccessibilityWindowId = other.mAccessibilityWindowId; + mBoundsInParent.set(other.mBoundsInParent); + mBoundsInScreen.set(other.mBoundsInScreen); + mPackageName = other.mPackageName; + mClassName = other.mClassName; + mText = other.mText; + mContentDescription = other.mContentDescription; + mActions= other.mActions; + mBooleanProperties = other.mBooleanProperties; + mChildAccessibilityIds = other.mChildAccessibilityIds.clone(); + } + + /** * Creates a new instance from a {@link Parcel}. * * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}. @@ -994,6 +1030,7 @@ public class AccessibilityNodeInfo implements Parcelable { mConnection = null; mAccessibilityViewId = View.NO_ID; mParentAccessibilityViewId = View.NO_ID; + mAccessibilityWindowId = View.NO_ID; mChildAccessibilityIds.clear(); mBoundsInParent.set(0, 0, 0, 0); mBoundsInScreen.set(0, 0, 0, 0); diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl index 1eb60fc..4e69692 100644 --- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl @@ -26,4 +26,5 @@ oneway interface IAccessibilityManagerClient { void setEnabled(boolean enabled); + void setTouchExplorationEnabled(boolean enabled); } diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index abe3c2c..5ec1ec3 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -34,7 +34,7 @@ import android.util.LogPrinter; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.View; -import android.view.ViewAncestor; +import android.view.ViewRootImpl; class ComposingText implements NoCopySpan { } @@ -502,7 +502,7 @@ public class BaseInputConnection implements InputConnection { } } if (h != null) { - h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME, + h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, event)); } } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index a1a7281..e5f3fc9 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -42,7 +42,7 @@ import android.util.Printer; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.ViewAncestor; +import android.view.ViewRootImpl; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -655,7 +655,7 @@ public final class InputMethodManager { if (vh != null) { // This will result in a call to reportFinishInputConnection() // below. - vh.sendMessage(vh.obtainMessage(ViewAncestor.FINISH_INPUT_CONNECTION, + vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION, mServedInputConnection)); } } @@ -1112,9 +1112,9 @@ public final class InputMethodManager { void scheduleCheckFocusLocked(View view) { Handler vh = view.getHandler(); - if (vh != null && !vh.hasMessages(ViewAncestor.CHECK_FOCUS)) { + if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) { // This will result in a call to checkFocus() below. - vh.sendMessage(vh.obtainMessage(ViewAncestor.CHECK_FOCUS)); + vh.sendMessage(vh.obtainMessage(ViewRootImpl.CHECK_FOCUS)); } } diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index 5aa60f4..738bcb9 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -35,7 +35,7 @@ import android.os.Message; import android.util.Log; import android.util.TypedValue; import android.view.Surface; -import android.view.ViewAncestor; +import android.view.ViewRootImpl; import android.view.WindowManager; import junit.framework.Assert; @@ -228,7 +228,7 @@ class BrowserFrame extends Handler { sConfigCallback = new ConfigCallback( (WindowManager) appContext.getSystemService( Context.WINDOW_SERVICE)); - ViewAncestor.addConfigCallback(sConfigCallback); + ViewRootImpl.addConfigCallback(sConfigCallback); } sConfigCallback.addHandler(this); diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index b9eb5ff..f82c61a 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -28,7 +28,7 @@ import android.util.Pair; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; -import com.android.internal.R.styleable; +import com.android.internal.R; import java.lang.reflect.Array; import java.util.ArrayList; @@ -167,7 +167,7 @@ public class GridLayout extends ViewGroup { // Misc constants private static final String TAG = GridLayout.class.getName(); - static final boolean DEBUG = false; + static boolean DEBUG = false; private static final int PRF = 1; // Defaults @@ -178,19 +178,17 @@ public class GridLayout extends ViewGroup { private static final boolean DEFAULT_ORDER_PRESERVED = false; private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS; private static final int DEFAULT_CONTAINER_MARGIN = 0; - private static final int DEFAULT_MARGIN = 8; - private static final int DEFAULT_CONTAINER_PADDING = 16; private static final int MAX_SIZE = 100000; // TypedArray indices - private static final int ORIENTATION = styleable.GridLayout_orientation; - private static final int ROW_COUNT = styleable.GridLayout_rowCount; - private static final int COLUMN_COUNT = styleable.GridLayout_columnCount; - private static final int USE_DEFAULT_MARGINS = styleable.GridLayout_useDefaultMargins; - private static final int ALIGNMENT_MODE = styleable.GridLayout_alignmentMode; - private static final int ROW_ORDER_PRESERVED = styleable.GridLayout_rowOrderPreserved; - private static final int COLUMN_ORDER_PRESERVED = styleable.GridLayout_columnOrderPreserved; + private static final int ORIENTATION = R.styleable.GridLayout_orientation; + private static final int ROW_COUNT = R.styleable.GridLayout_rowCount; + private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount; + private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins; + private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode; + private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved; + private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved; // Instance variables @@ -201,6 +199,7 @@ public class GridLayout extends ViewGroup { private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS; private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE; private int mDefaultGravity = Gravity.NO_GRAVITY; + private int mDefaultGap; // Constructors @@ -212,7 +211,8 @@ public class GridLayout extends ViewGroup { if (DEBUG) { setWillNotDraw(false); } - TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout); + mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout); try { setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT)); setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT)); @@ -382,7 +382,7 @@ public class GridLayout extends ViewGroup { public void setUseDefaultMargins(boolean useDefaultMargins) { mUseDefaultMargins = useDefaultMargins; if (useDefaultMargins) { - int padding = DEFAULT_CONTAINER_PADDING; + int padding = mDefaultGap; setPadding(padding, padding, padding, padding); } requestLayout(); @@ -538,7 +538,7 @@ public class GridLayout extends ViewGroup { } private int getDefaultMargin(View c, boolean horizontal, boolean leading) { - return DEFAULT_MARGIN; + return mDefaultGap / 2; } private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) { @@ -787,6 +787,12 @@ public class GridLayout extends ViewGroup { invalidateStructure(); } + @Override + public void removeAllViews() { + super.removeAllViews(); + invalidateStructure(); + } + // Measurement private boolean isGone(View c) { @@ -1596,8 +1602,8 @@ public class GridLayout extends ViewGroup { * each cell group. The fundamental parameters associated with each cell group are * gathered into their vertical and horizontal components and stored * in the {@link #rowSpec} and {@link #columnSpec} layout parameters. - * {@link android.widget.GridLayout.Spec Specs} are immutable structures and may be shared between the layout - * parameters of different children. + * {@link android.widget.GridLayout.Spec Specs} are immutable structures + * and may be shared between the layout parameters of different children. * <p> * The row and column specs contain the leading and trailing indices along each axis * and together specify the four grid indices that delimit the cells of this cell group. @@ -1667,24 +1673,25 @@ public class GridLayout extends ViewGroup { // TypedArray indices - private static final int MARGIN = styleable.ViewGroup_MarginLayout_layout_margin; - private static final int LEFT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginLeft; - private static final int TOP_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginTop; - private static final int RIGHT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginRight; + private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin; + private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft; + private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop; + private static final int RIGHT_MARGIN = + R.styleable.ViewGroup_MarginLayout_layout_marginRight; private static final int BOTTOM_MARGIN = - styleable.ViewGroup_MarginLayout_layout_marginBottom; + R.styleable.ViewGroup_MarginLayout_layout_marginBottom; - private static final int COLUMN = styleable.GridLayout_Layout_layout_column; - private static final int COLUMN_SPAN = styleable.GridLayout_Layout_layout_columnSpan; + private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column; + private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan; private static final int COLUMN_FLEXIBILITY = - styleable.GridLayout_Layout_layout_columnFlexibility; + R.styleable.GridLayout_Layout_layout_columnFlexibility; - private static final int ROW = styleable.GridLayout_Layout_layout_row; - private static final int ROW_SPAN = styleable.GridLayout_Layout_layout_rowSpan; + private static final int ROW = R.styleable.GridLayout_Layout_layout_row; + private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan; private static final int ROW_FLEXIBILITY = - styleable.GridLayout_Layout_layout_rowFlexibility; + R.styleable.GridLayout_Layout_layout_rowFlexibility; - private static final int GRAVITY = styleable.GridLayout_Layout_layout_gravity; + private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity; // Instance variables @@ -1804,7 +1811,8 @@ public class GridLayout extends ViewGroup { // This method could be parametrized and moved into MarginLayout. private void reInitSuper(Context context, AttributeSet attrs) { - TypedArray a = context.obtainStyledAttributes(attrs, styleable.ViewGroup_MarginLayout); + TypedArray a = + context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout); try { int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN); @@ -1840,7 +1848,7 @@ public class GridLayout extends ViewGroup { } private void init(Context context, AttributeSet attrs, int defaultGravity) { - TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout_Layout); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout); try { int gravity = a.getInt(GRAVITY, defaultGravity); @@ -2301,10 +2309,10 @@ public class GridLayout extends ViewGroup { */ @Deprecated public static class Group extends Spec { - /** - * @deprecated Please replace with {@link #spec(int, int, Alignment)} - * @hide - */ + /** + * @deprecated Please replace with {@link #spec(int, int, Alignment)} + * @hide + */ @Deprecated public Group(int start, int size, Alignment alignment) { super(start, size, alignment, UNDEFINED_FLEXIBILITY); diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index f3bda43..b2d1a1e 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -18,8 +18,6 @@ package android.widget; import static android.widget.SuggestionsAdapter.getColumnString; -import com.android.internal.R; - import android.app.PendingIntent; import android.app.SearchManager; import android.app.SearchableInfo; @@ -39,10 +37,14 @@ import android.net.Uri; import android.os.Bundle; import android.speech.RecognizerIntent; import android.text.Editable; +import android.text.Spannable; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.TextWatcher; +import android.text.style.ImageSpan; import android.util.AttributeSet; import android.util.Log; +import android.util.TypedValue; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -51,6 +53,8 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.TextView.OnEditorActionListener; +import com.android.internal.R; + import java.util.WeakHashMap; /** @@ -87,6 +91,8 @@ public class SearchView extends LinearLayout { private View mSearchEditFrame; private View mVoiceButton; private SearchAutoComplete mQueryTextView; + private View mDropDownAnchor; + private ImageView mSearchHintIcon; private boolean mSubmitButtonEnabled; private CharSequence mQueryHint; private boolean mQueryRefinement; @@ -195,6 +201,7 @@ public class SearchView extends LinearLayout { mSubmitButton = findViewById(R.id.search_go_btn); mCloseButton = (ImageView) findViewById(R.id.search_close_btn); mVoiceButton = findViewById(R.id.search_voice_btn); + mSearchHintIcon = (ImageView) findViewById(R.id.search_mag_icon); mSearchButton.setOnClickListener(mOnClickListener); mCloseButton.setOnClickListener(mOnClickListener); @@ -244,7 +251,20 @@ public class SearchView extends LinearLayout { mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mDropDownAnchor = findViewById(mQueryTextView.getDropDownAnchor()); + if (mDropDownAnchor != null) { + mDropDownAnchor.addOnLayoutChangeListener(new OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + adjustDropDownSizeAndPosition(); + } + + }); + } + updateViewsVisibility(mIconifiedByDefault); + updateQueryHint(); } /** @@ -263,7 +283,7 @@ public class SearchView extends LinearLayout { } // Cache the voice search capability mVoiceButtonEnabled = hasVoiceSearch(); - updateViewsVisibility(mIconifiedByDefault); + updateViewsVisibility(isIconified()); } /** @@ -300,7 +320,6 @@ public class SearchView extends LinearLayout { mQueryTextView.clearFocus(); setImeVisibility(false); mClearingFocus = false; - updateViewsVisibility(mIconifiedByDefault); } /** @@ -555,6 +574,7 @@ public class SearchView extends LinearLayout { mSearchButton.setVisibility(visCollapsed); updateSubmitButton(hasText); mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE); + mSearchHintIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE); updateCloseButton(); updateVoiceButton(!hasText); updateSubmitArea(); @@ -822,9 +842,29 @@ public class SearchView extends LinearLayout { return result; } + private int getSearchIconId() { + TypedValue outValue = new TypedValue(); + getContext().getTheme().resolveAttribute(com.android.internal.R.attr.searchViewSearchIcon, + outValue, true); + return outValue.resourceId; + } + + private CharSequence getDecoratedHint(CharSequence hintText) { + // If the field is always expanded, then don't add the search icon to the hint + if (!mIconifiedByDefault) return hintText; + + SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // for the icon + ssb.append(hintText); + Drawable searchIcon = getContext().getResources().getDrawable(getSearchIconId()); + int textSize = (int) (mQueryTextView.getTextSize() * 1.25); + searchIcon.setBounds(0, 0, textSize, textSize); + ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return ssb; + } + private void updateQueryHint() { if (mQueryHint != null) { - mQueryTextView.setHint(mQueryHint); + mQueryTextView.setHint(getDecoratedHint(mQueryHint)); } else if (mSearchable != null) { CharSequence hint = null; int hintId = mSearchable.getHintId(); @@ -832,8 +872,10 @@ public class SearchView extends LinearLayout { hint = getContext().getString(hintId); } if (hint != null) { - mQueryTextView.setHint(hint); + mQueryTextView.setHint(getDecoratedHint(hint)); } + } else { + mQueryTextView.setHint(getDecoratedHint("")); } } @@ -922,9 +964,13 @@ public class SearchView extends LinearLayout { CharSequence text = mQueryTextView.getText(); if (TextUtils.isEmpty(text)) { if (mIconifiedByDefault) { - // query field already empty, hide the keyboard and remove focus - clearFocus(); - setImeVisibility(false); + // If the app doesn't override the close behavior + if (mOnCloseListener == null || !mOnCloseListener.onClose()) { + // hide the keyboard and remove focus + clearFocus(); + // collapse the search field + updateViewsVisibility(true); + } } } else { mQueryTextView.setText(""); @@ -932,10 +978,6 @@ public class SearchView extends LinearLayout { setImeVisibility(true); } - if (mIconifiedByDefault && (mOnCloseListener == null || !mOnCloseListener.onClose())) { - updateViewsVisibility(mIconifiedByDefault); - setImeVisibility(false); - } } private void onSearchClicked() { @@ -975,6 +1017,28 @@ public class SearchView extends LinearLayout { updateFocusedState(mQueryTextView.hasFocus()); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + } + + private void adjustDropDownSizeAndPosition() { + if (mDropDownAnchor.getWidth() > 1) { + Resources res = getContext().getResources(); + int anchorPadding = mSearchPlate.getPaddingLeft(); + Rect dropDownPadding = new Rect(); + int iconOffset = mIconifiedByDefault + ? res.getDimensionPixelSize(R.dimen.dropdownitem_icon_width) + + res.getDimensionPixelSize(R.dimen.dropdownitem_text_padding_left) + : 0; + mQueryTextView.getDropDownBackground().getPadding(dropDownPadding); + mQueryTextView.setDropDownHorizontalOffset(-(dropDownPadding.left + iconOffset) + + anchorPadding); + mQueryTextView.setDropDownWidth(mDropDownAnchor.getWidth() + dropDownPadding.left + + dropDownPadding.right + iconOffset - (anchorPadding)); + } + } + private boolean onItemClicked(int position, int actionKey, String actionMsg) { if (mOnSuggestionListener == null || !mOnSuggestionListener.onSuggestionClick(position)) { @@ -1393,5 +1457,32 @@ public class SearchView extends LinearLayout { public boolean enoughToFilter() { return mThreshold <= 0 || super.enoughToFilter(); } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + // special case for the back key, we do not even try to send it + // to the drop down list but instead, consume it immediately + if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.startTracking(event, this); + } + return true; + } else if (event.getAction() == KeyEvent.ACTION_UP) { + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.handleUpEvent(event); + } + if (event.isTracking() && !event.isCanceled()) { + mSearchView.clearFocus(); + mSearchView.setImeVisibility(false); + return true; + } + } + } + return super.onKeyPreIme(keyCode, event); + } + } } diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java index 2cfc016..9e32c9a 100644 --- a/core/java/android/widget/SuggestionsAdapter.java +++ b/core/java/android/widget/SuggestionsAdapter.java @@ -16,8 +16,6 @@ package android.widget; -import com.android.internal.R; - import android.app.SearchDialog; import android.app.SearchManager; import android.app.SearchableInfo; @@ -47,6 +45,8 @@ import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; +import com.android.internal.R; + import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -88,8 +88,8 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene private int mIconName2Col = INVALID_INDEX; private int mFlagsCol = INVALID_INDEX; - private final Runnable mStartSpinnerRunnable; - private final Runnable mStopSpinnerRunnable; + // private final Runnable mStartSpinnerRunnable; + // private final Runnable mStopSpinnerRunnable; /** * The amount of time we delay in the filter when the user presses the delete key. @@ -113,17 +113,18 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene mOutsideDrawablesCache = outsideDrawablesCache; - mStartSpinnerRunnable = new Runnable() { - public void run() { - // mSearchView.setWorking(true); // TODO: - } - }; - mStopSpinnerRunnable = new Runnable() { - public void run() { - // mSearchView.setWorking(false); // TODO: - } - }; + // mStartSpinnerRunnable = new Runnable() { + // public void run() { + // // mSearchView.setWorking(true); // TODO: + // } + // }; + // + // mStopSpinnerRunnable = new Runnable() { + // public void run() { + // // mSearchView.setWorking(false); // TODO: + // } + // }; // delay 500ms when deleting getFilter().setDelayer(new Filter.Delayer() { @@ -341,10 +342,10 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene } if (views.mIcon1 != null) { - setViewDrawable(views.mIcon1, getIcon1(cursor)); + setViewDrawable(views.mIcon1, getIcon1(cursor), View.INVISIBLE); } if (views.mIcon2 != null) { - setViewDrawable(views.mIcon2, getIcon2(cursor)); + setViewDrawable(views.mIcon2, getIcon2(cursor), View.GONE); } if (mQueryRefinement == REFINE_ALL || (mQueryRefinement == REFINE_BY_ENTRY @@ -414,13 +415,13 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene * Sets the drawable in an image view, makes sure the view is only visible if there * is a drawable. */ - private void setViewDrawable(ImageView v, Drawable drawable) { + private void setViewDrawable(ImageView v, Drawable drawable, int nullVisibility) { // Set the icon even if the drawable is null, since we need to clear any // previous icon. v.setImageDrawable(drawable); if (drawable == null) { - v.setVisibility(View.GONE); + v.setVisibility(nullVisibility); } else { v.setVisibility(View.VISIBLE); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 769f5e3..66a07d3 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -117,7 +117,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.ViewAncestor; +import android.view.ViewRootImpl; import android.view.ViewConfiguration; import android.view.ViewDebug; import android.view.ViewGroup; @@ -3731,13 +3731,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Handler h = getHandler(); if (h != null) { long eventTime = SystemClock.uptimeMillis(); - h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME, + h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE | KeyEvent.FLAG_EDITOR_ACTION))); - h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME, + h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, new KeyEvent(SystemClock.uptimeMillis(), eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java index 9e37c7b..f3d891d 100644 --- a/core/java/android/widget/ZoomButtonsController.java +++ b/core/java/android/widget/ZoomButtonsController.java @@ -33,7 +33,7 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; -import android.view.ViewAncestor; +import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.View.OnClickListener; import android.view.WindowManager.LayoutParams; @@ -501,7 +501,7 @@ public class ZoomButtonsController implements View.OnTouchListener { } else { - ViewAncestor viewRoot = getOwnerViewAncestor(); + ViewRootImpl viewRoot = getOwnerViewRootImpl(); if (viewRoot != null) { viewRoot.dispatchKey(event); } @@ -526,15 +526,15 @@ public class ZoomButtonsController implements View.OnTouchListener { } } - private ViewAncestor getOwnerViewAncestor() { + private ViewRootImpl getOwnerViewRootImpl() { View rootViewOfOwner = mOwnerView.getRootView(); if (rootViewOfOwner == null) { return null; } ViewParent parentOfRootView = rootViewOfOwner.getParent(); - if (parentOfRootView instanceof ViewAncestor) { - return (ViewAncestor) parentOfRootView; + if (parentOfRootView instanceof ViewRootImpl) { + return (ViewRootImpl) parentOfRootView; } else { return null; } |