diff options
Diffstat (limited to 'core/java')
32 files changed, 578 insertions, 731 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 68c9926..1e238f0 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -130,20 +130,11 @@ import android.view.accessibility.AccessibilityNodeInfo; * For security purposes an accessibility service can retrieve only the content of the * currently active window. The currently active window is defined as the window from * which was fired the last event of the following types: - * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}, - * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}, - * {@link AccessibilityEvent#TYPE_VIEW_CLICKED}, - * {@link AccessibilityEvent#TYPE_VIEW_FOCUSED}, + * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}, * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}, * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}, - * {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}, - * {@link AccessibilityEvent#TYPE_VIEW_SELECTED}, - * {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}, - * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}, - * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED}, - * {@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}, - * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}. - * In other words, the active window is the one where the user interaction is taking place. + * In other words, the last window that was shown or the last window that the user has touched + * during touch exploration. * </p> * <p> * The entry point for retrieving window content is through calling diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index 36940c2..a217867 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -29,10 +29,16 @@ import android.view.Window; import android.widget.SpinnerAdapter; /** - * This is the public interface to the contextual ActionBar. - * The ActionBar acts as a replacement for the title bar in Activities. - * It provides facilities for creating toolbar actions as well as - * methods of navigating around an application. + * Acts as a replacement for the title bar in Activities. + * The action bar provides facilities for creating toolbar actions as well as + * methods of navigating the application. + * <p>By default, the action bar appears at the top of every activity, with the application icon on + * the left, followed by the activity title. Items from the activity's options menu are also + * accessible from the action bar.</p> + * <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link + * android.app.Activity#getActionBar getActionBar()}.</p> + * <p>For more information, read the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action + * Bar</a> developer guide.</p> */ public abstract class ActionBar { /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9bbbd6c..1e93f88 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -123,7 +123,6 @@ public final class ActivityThread { /** @hide */ public static final String TAG = "ActivityThread"; private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565; - private static final boolean DEBUG = false; static final boolean localLOGV = false; static final boolean DEBUG_MESSAGES = false; /** @hide */ @@ -163,7 +162,7 @@ public final class ActivityThread { = new ArrayList<Application>(); // set of instantiated backup agents, keyed by package name final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>(); - static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal(); + static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal<ActivityThread>(); Instrumentation mInstrumentation; String mInstrumentationAppDir = null; String mInstrumentationAppPackage = null; @@ -410,9 +409,9 @@ public final class ActivityThread { CompatibilityInfo info; } - native private void dumpGraphicsInfo(FileDescriptor fd); + private native void dumpGraphicsInfo(FileDescriptor fd); - private final class ApplicationThread extends ApplicationThreadNative { + private class ApplicationThread extends ApplicationThreadNative { private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s"; private static final String ONE_COUNT_COLUMN = "%21s %8d"; private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d"; @@ -734,13 +733,13 @@ public final class ActivityThread { FileOutputStream fout = new FileOutputStream(fd); PrintWriter pw = new PrintWriter(fout); try { - return dumpMemInfo(fd, pw, args); + return dumpMemInfo(pw, args); } finally { pw.flush(); } } - private Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, PrintWriter pw, String[] args) { + private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, String[] args) { long nativeMax = Debug.getNativeHeapSize() / 1024; long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024; long nativeFree = Debug.getNativeHeapFreeSize() / 1024; @@ -754,7 +753,7 @@ public final class ActivityThread { long dalvikFree = runtime.freeMemory() / 1024; long dalvikAllocated = dalvikMax - dalvikFree; long viewInstanceCount = ViewDebug.getViewInstanceCount(); - long viewRootInstanceCount = ViewDebug.getViewAncestorInstanceCount(); + long viewRootInstanceCount = ViewDebug.getViewRootImplCount(); long appContextInstanceCount = Debug.countInstancesOfClass(ContextImpl.class); long activityInstanceCount = Debug.countInstancesOfClass(Activity.class); int globalAssetCount = AssetManager.getGlobalAssetCount(); @@ -868,7 +867,7 @@ public final class ActivityThread { int otherPrivateDirty = memInfo.otherPrivateDirty; for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) { - printRow(pw, HEAP_COLUMN, memInfo.getOtherLabel(i), + printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i), memInfo.getOtherPss(i), memInfo.getOtherSharedDirty(i), memInfo.getOtherPrivateDirty(i), "", "", ""); otherPss -= memInfo.getOtherPss(i); @@ -885,7 +884,7 @@ public final class ActivityThread { pw.println(" "); pw.println(" Objects"); - printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewAncestors:", + printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRootImpl:", viewRootInstanceCount); printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount, @@ -937,6 +936,7 @@ public final class ActivityThread { @Override public void dumpGfxInfo(FileDescriptor fd, String[] args) { dumpGraphicsInfo(fd); + WindowManagerImpl.getDefault().dumpGfxInfo(fd); } private void printRow(PrintWriter pw, String format, Object...objs) { @@ -959,7 +959,7 @@ public final class ActivityThread { } } - private final class H extends Handler { + private class H extends Handler { public static final int LAUNCH_ACTIVITY = 100; public static final int PAUSE_ACTIVITY = 101; public static final int PAUSE_ACTIVITY_FINISHING= 102; @@ -1220,7 +1220,7 @@ public final class ActivityThread { } } - private final class Idler implements MessageQueue.IdleHandler { + private class Idler implements MessageQueue.IdleHandler { public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; if (a != null) { @@ -1231,12 +1231,13 @@ public final class ActivityThread { if (localLOGV) Slog.v( TAG, "Reporting idle of " + a + " finished=" + - (a.activity != null ? a.activity.mFinished : false)); + (a.activity != null && a.activity.mFinished)); if (a.activity != null && !a.activity.mFinished) { try { am.activityIdle(a.token, a.createdConfig); a.createdConfig = null; } catch (RemoteException ex) { + // Ignore } } prev = a; @@ -1256,7 +1257,7 @@ public final class ActivityThread { } } - private final static class ResourcesKey { + private static class ResourcesKey { final private String mResDir; final private float mScale; final private int mHash; @@ -1282,17 +1283,17 @@ public final class ActivityThread { } } - public static final ActivityThread currentActivityThread() { + public static ActivityThread currentActivityThread() { return sThreadLocal.get(); } - public static final String currentPackageName() { + public static String currentPackageName() { ActivityThread am = currentActivityThread(); return (am != null && am.mBoundApplication != null) ? am.mBoundApplication.processName : null; } - public static final Application currentApplication() { + public static Application currentApplication() { ActivityThread am = currentActivityThread(); return am != null ? am.mInitialApplication : null; } @@ -1337,7 +1338,7 @@ public final class ActivityThread { return config; } - private final Configuration mMainThreadConfig = new Configuration(); + private Configuration mMainThreadConfig = new Configuration(); Configuration applyConfigCompatMainThread(Configuration config, CompatibilityInfo compat) { if (config == null) { return null; @@ -1456,6 +1457,7 @@ public final class ActivityThread { ai = getPackageManager().getApplicationInfo(packageName, PackageManager.GET_SHARED_LIBRARY_FILES); } catch (RemoteException e) { + // Ignore } if (ai != null) { @@ -1505,7 +1507,7 @@ public final class ActivityThread { } } - private final LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo, + private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo, ClassLoader baseLoader, boolean securityViolation, boolean includeCode) { synchronized (mPackages) { WeakReference<LoadedApk> ref; @@ -1712,15 +1714,15 @@ public final class ActivityThread { // if the thread hasn't started yet, we don't have the handler, so just // save the messages until we're ready. - private final void queueOrSendMessage(int what, Object obj) { + private void queueOrSendMessage(int what, Object obj) { queueOrSendMessage(what, obj, 0, 0); } - private final void queueOrSendMessage(int what, Object obj, int arg1) { + private void queueOrSendMessage(int what, Object obj, int arg1) { queueOrSendMessage(what, obj, arg1, 0); } - private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) { + private void queueOrSendMessage(int what, Object obj, int arg1, int arg2) { synchronized (this) { if (DEBUG_MESSAGES) Slog.v( TAG, "SCHEDULE " + what + " " + mH.codeToString(what) @@ -1743,7 +1745,7 @@ public final class ActivityThread { queueOrSendMessage(H.CLEAN_UP_CONTEXT, cci); } - private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { + private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; @@ -1861,7 +1863,7 @@ public final class ActivityThread { return activity; } - private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { + private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -1917,11 +1919,12 @@ public final class ActivityThread { ActivityManagerNative.getDefault() .finishActivity(r.token, Activity.RESULT_CANCELED, null); } catch (RemoteException ex) { + // Ignore } } } - private final void deliverNewIntents(ActivityClientRecord r, + private void deliverNewIntents(ActivityClientRecord r, List<Intent> intents) { final int N = intents.size(); for (int i=0; i<N; i++) { @@ -1949,7 +1952,7 @@ public final class ActivityThread { } } - private final void handleNewIntent(NewIntentData data) { + private void handleNewIntent(NewIntentData data) { performNewIntents(data.token, data.intents); } @@ -1964,7 +1967,7 @@ public final class ActivityThread { return sCurrentBroadcastIntent.get(); } - private final void handleReceiver(ReceiverData data) { + private void handleReceiver(ReceiverData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -1976,7 +1979,7 @@ public final class ActivityThread { IActivityManager mgr = ActivityManagerNative.getDefault(); - BroadcastReceiver receiver = null; + BroadcastReceiver receiver; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); data.intent.setExtrasClassLoader(cl); @@ -2026,7 +2029,7 @@ public final class ActivityThread { } // Instantiate a BackupAgent and tell it that it's alive - private final void handleCreateBackupAgent(CreateBackupAgentData data) { + private void handleCreateBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleCreateBackupAgent: " + data); // no longer idle; we have backup work to do @@ -2091,7 +2094,7 @@ public final class ActivityThread { } // Tear down a BackupAgent - private final void handleDestroyBackupAgent(CreateBackupAgentData data) { + private void handleDestroyBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data); LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo); @@ -2110,7 +2113,7 @@ public final class ActivityThread { } } - private final void handleCreateService(CreateServiceData data) { + private void handleCreateService(CreateServiceData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -2156,7 +2159,7 @@ public final class ActivityThread { } } - private final void handleBindService(BindServiceData data) { + private void handleBindService(BindServiceData data) { Service s = mServices.get(data.token); if (s != null) { try { @@ -2184,7 +2187,7 @@ public final class ActivityThread { } } - private final void handleUnbindService(BindServiceData data) { + private void handleUnbindService(BindServiceData data) { Service s = mServices.get(data.token); if (s != null) { try { @@ -2236,7 +2239,7 @@ public final class ActivityThread { } } - private final void handleServiceArgs(ServiceArgsData data) { + private void handleServiceArgs(ServiceArgsData data) { Service s = mServices.get(data.token); if (s != null) { try { @@ -2270,7 +2273,7 @@ public final class ActivityThread { } } - private final void handleStopService(IBinder token) { + private void handleStopService(IBinder token) { Service s = mServices.remove(token); if (s != null) { try { @@ -2465,7 +2468,7 @@ public final class ActivityThread { private Bitmap mAvailThumbnailBitmap = null; private Canvas mThumbnailCanvas = null; - private final Bitmap createThumbnailBitmap(ActivityClientRecord r) { + private Bitmap createThumbnailBitmap(ActivityClientRecord r) { Bitmap thumbnail = mAvailThumbnailBitmap; try { if (thumbnail == null) { @@ -2515,7 +2518,7 @@ public final class ActivityThread { return thumbnail; } - private final void handlePauseActivity(IBinder token, boolean finished, + private void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges) { ActivityClientRecord r = mActivities.get(token); if (r != null) { @@ -2621,7 +2624,7 @@ public final class ActivityThread { CharSequence description; } - private final class ProviderRefCount { + private class ProviderRefCount { public int count; ProviderRefCount(int pCount) { count = pCount; @@ -2636,7 +2639,7 @@ public final class ActivityThread { * For the client, we want to call onStop()/onStart() to indicate when * the activity's UI visibillity changes. */ - private final void performStopActivityInner(ActivityClientRecord r, + private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown, boolean saveState) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); Bundle state = null; @@ -2699,7 +2702,7 @@ public final class ActivityThread { } } - private final void updateVisibility(ActivityClientRecord r, boolean show) { + private void updateVisibility(ActivityClientRecord r, boolean show) { View v = r.activity.mDecor; if (v != null) { if (show) { @@ -2726,7 +2729,7 @@ public final class ActivityThread { } } - private final void handleStopActivity(IBinder token, boolean show, int configChanges) { + private void handleStopActivity(IBinder token, boolean show, int configChanges) { ActivityClientRecord r = mActivities.get(token); r.activity.mConfigChangeFlags |= configChanges; @@ -2760,7 +2763,7 @@ public final class ActivityThread { } } - private final void handleWindowVisibility(IBinder token, boolean show) { + private void handleWindowVisibility(IBinder token, boolean show) { ActivityClientRecord r = mActivities.get(token); if (r == null) { @@ -2785,7 +2788,7 @@ public final class ActivityThread { } } - private final void handleSleeping(IBinder token, boolean sleeping) { + private void handleSleeping(IBinder token, boolean sleeping) { ActivityClientRecord r = mActivities.get(token); if (r == null) { @@ -2846,7 +2849,7 @@ public final class ActivityThread { WindowManagerImpl.getDefault().reportNewConfiguration(mConfiguration); } - private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) { + private void deliverResults(ActivityClientRecord r, List<ResultInfo> results) { final int N = results.size(); for (int i=0; i<N; i++) { ResultInfo ri = results.get(i); @@ -2869,7 +2872,7 @@ public final class ActivityThread { } } - private final void handleSendResult(ResultData res) { + private void handleSendResult(ResultData res) { ActivityClientRecord r = mActivities.get(res.token); if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r); if (r != null) { @@ -2915,7 +2918,7 @@ public final class ActivityThread { return performDestroyActivity(token, finishing, 0, false); } - private final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, + private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance) { ActivityClientRecord r = mActivities.get(token); Class activityClass = null; @@ -3008,7 +3011,7 @@ public final class ActivityThread { return component == null ? "[Unknown]" : component.toShortString(); } - private final void handleDestroyActivity(IBinder token, boolean finishing, + private void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance) { ActivityClientRecord r = performDestroyActivity(token, finishing, configChanges, getNonConfigInstance); @@ -3123,7 +3126,7 @@ public final class ActivityThread { } } - private final void handleRelaunchActivity(ActivityClientRecord tmp) { + private void handleRelaunchActivity(ActivityClientRecord tmp) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -3233,7 +3236,7 @@ public final class ActivityThread { handleLaunchActivity(r, currentIntent); } - private final void handleRequestThumbnail(IBinder token) { + private void handleRequestThumbnail(IBinder token) { ActivityClientRecord r = mActivities.get(token); Bitmap thumbnail = createThumbnailBitmap(r); CharSequence description = null; @@ -3308,7 +3311,7 @@ public final class ActivityThread { return callbacks; } - private final void performConfigurationChanged( + private void performConfigurationChanged( ComponentCallbacks cb, Configuration config) { // Only for Activity objects, check that they actually call up to their // superclass implementation. ComponentCallbacks is an interface, so @@ -3451,6 +3454,9 @@ public final class ActivityThread { } callbacks = collectComponentCallbacksLocked(false, config); } + + // Cleanup hardware accelerated stuff + WindowManagerImpl.getDefault().trimLocalMemory(); if (callbacks != null) { final int N = callbacks.size(); @@ -3579,7 +3585,7 @@ public final class ActivityThread { WindowManagerImpl.getDefault().trimMemory(level); } - private final void handleBindApplication(AppBindData data) { + private void handleBindApplication(AppBindData data) { mBoundApplication = data; mConfiguration = new Configuration(data.config); mCompatConfiguration = new Configuration(data.config); @@ -3791,7 +3797,7 @@ public final class ActivityThread { } } - private final void installContentProviders( + private void installContentProviders( Context context, List<ProviderInfo> providers) { final ArrayList<IActivityManager.ContentProviderHolder> results = new ArrayList<IActivityManager.ContentProviderHolder>(); @@ -3825,7 +3831,7 @@ public final class ActivityThread { } } - private final IContentProvider getExistingProvider(Context context, String name) { + private IContentProvider getExistingProvider(Context context, String name) { synchronized(mProviderMap) { final ProviderClientRecord pr = mProviderMap.get(name); if (pr != null) { @@ -3835,7 +3841,7 @@ public final class ActivityThread { } } - private final IContentProvider getProvider(Context context, String name) { + private IContentProvider getProvider(Context context, String name) { IContentProvider existing = getExistingProvider(context, name); if (existing != null) { return existing; @@ -4007,7 +4013,7 @@ public final class ActivityThread { } } - private final IContentProvider installProvider(Context context, + private IContentProvider installProvider(Context context, IContentProvider provider, ProviderInfo info, boolean noisy) { ContentProvider localProvider = null; if (provider == null) { @@ -4027,6 +4033,7 @@ public final class ActivityThread { c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { + // Ignore } } if (c == null) { @@ -4086,7 +4093,7 @@ public final class ActivityThread { return provider; } - private final void attach(boolean system) { + private void attach(boolean system) { sThreadLocal.set(this); mSystemThread = system; if (!system) { @@ -4101,6 +4108,7 @@ public final class ActivityThread { try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { + // Ignore } } else { // Don't set application object here -- if the system crashes, @@ -4166,7 +4174,7 @@ public final class ActivityThread { } } - public static final void main(String[] args) { + public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index cb97c46..e2746d4 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -162,6 +162,9 @@ final class FragmentState implements Parcelable { * constructor to instantiate it. If the empty constructor is not available, * a runtime exception will occur in some cases during state restore. * + * <p>For more documentation, also see the <a + * href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p> + * * <p>Topics covered here: * <ol> * <li><a href="#OlderPlatforms">Older Platforms</a> @@ -880,7 +883,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener public void setHasOptionsMenu(boolean hasMenu) { if (mHasMenu != hasMenu) { mHasMenu = hasMenu; - if (isAdded() && !isHidden()) { + if (isAdded() && !isHidden() && isResumed()) { mActivity.invalidateOptionsMenu(); } } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 789d3a6..24550c5 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -978,7 +978,7 @@ final class FragmentManagerImpl extends FragmentManager { } } - if (mNeedMenuInvalidate && mActivity != null) { + if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) { mActivity.invalidateOptionsMenu(); mNeedMenuInvalidate = false; } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index cdda910..2a02446 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -129,7 +129,7 @@ public abstract class Context { /** * Flag for {@link #bindService}: don't allow this binding to raise * the target service's process to the foreground scheduling priority. - * It will still be raised to the at least the same memory priority + * It will still be raised to at least the same memory priority * as the client (so that its process will not be killable in any * situation where the client is not killable), but for CPU scheduling * purposes it may be left in the background. This only has an impact @@ -138,6 +138,16 @@ public abstract class Context { */ public static final int BIND_NOT_FOREGROUND = 0x0004; + /** + * Flag for {@link #bindService}: allow the process hosting the bound + * service to go through its normal memory management. It will be + * treated more like a running service, allowing the system to + * (temporarily) expunge the process if low on memory or for some other + * whim it may have. + * @hide + */ + public static final int BIND_ALLOW_OOM_MANAGEMENT = 0x0008; + /** Return an AssetManager instance for your application's package. */ public abstract AssetManager getAssets(); diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java index 4e70b74..368c33e 100644 --- a/core/java/android/content/Loader.java +++ b/core/java/android/content/Loader.java @@ -40,6 +40,8 @@ import java.io.PrintWriter; * * <p>Most implementations should not derive directly from this class, but * instead inherit from {@link AsyncTaskLoader}.</p> + * <p>For more information, see the <a + * href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> developer guide.</p> * * @param <D> The result returned when the load is complete */ diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 2cb8a86..5be6ec1 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -1691,12 +1691,28 @@ public class SyncManager implements OnAccountsUpdateListener { continue; } - // skip the sync if it isn't manual and auto sync or - // background data usage is disabled + final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo; + syncAdapterInfo = mSyncAdapters.getServiceInfo( + SyncAdapterType.newKey(op.authority, op.account.type)); + + // only proceed if network is connected for requesting UID + final boolean uidNetworkConnected; + if (syncAdapterInfo != null) { + final NetworkInfo networkInfo = getConnectivityManager() + .getActiveNetworkInfoForUid(syncAdapterInfo.uid); + uidNetworkConnected = networkInfo != null && networkInfo.isConnected(); + } else { + uidNetworkConnected = false; + } + + // skip the sync if it isn't manual, and auto sync or + // background data usage is disabled or network is + // disconnected for the target UID. if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false) && (syncableState > 0) && (!masterSyncAutomatically || !backgroundDataUsageAllowed + || !uidNetworkConnected || !mSyncStorageEngine.getSyncAutomatically( op.account, op.authority))) { operationIterator.remove(); diff --git a/core/java/android/net/VpnBuilder.java b/core/java/android/net/VpnBuilder.java index 4582523..25cedb6 100644 --- a/core/java/android/net/VpnBuilder.java +++ b/core/java/android/net/VpnBuilder.java @@ -91,7 +91,6 @@ import java.util.ArrayList; * * <p class="note">Using this class requires * {@link android.Manifest.permission#VPN} permission. - * @hide */ public class VpnBuilder { diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index b2c1386..5765dde 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1973,6 +1973,16 @@ public final class ContactsContract { public static final String DATA_SET = "data_set"; /** + * A concatenation of the account type and data set (delimited by a forward + * slash) - if the data set is empty, this will be the same as the account + * type. For applications that need to be aware of the data set, this can + * be used instead of account type to distinguish sets of data. This is + * never intended to be used for specifying accounts. + * @hide + */ + public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set"; + + /** * The aggregation mode for this contact. * <P>Type: INTEGER</P> */ @@ -6444,6 +6454,16 @@ public final class ContactsContract { public static final String DATA_SET = "data_set"; /** + * A concatenation of the account type and data set (delimited by a forward + * slash) - if the data set is empty, this will be the same as the account + * type. For applications that need to be aware of the data set, this can + * be used instead of account type to distinguish sets of data. This is + * never intended to be used for specifying accounts. + * @hide + */ + public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set"; + + /** * The display title of this group. * <p> * Type: TEXT @@ -7871,6 +7891,19 @@ public final class ContactsContract { * @hide */ public static final String ACCOUNT = "com.android.contacts.extra.ACCOUNT"; + + /** + * Used to specify the data set within the account in which to create the + * new contact. + * <p> + * This value is optional - if it is not specified, the contact will be + * created in the base account, with no data set. + * <p> + * Type: String + * + * @hide + */ + public static final String DATA_SET = "com.android.contacts.extra.DATA_SET"; } } } diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 5ab2024..d9efe0c 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -25,16 +25,18 @@ import android.os.SystemClock; import android.util.DisplayMetrics; import android.util.Slog; +/** + * Provides information about the display size and density. + */ public class Display { static final String TAG = "Display"; static final boolean DEBUG_COMPAT = false; /** - * Specify the default Display + * The default Display id. */ public static final int DEFAULT_DISPLAY = 0; - /** * Use {@link android.view.WindowManager#getDefaultDisplay() * WindowManager.getDefaultDisplay()} to create a Display object. @@ -55,16 +57,6 @@ public class Display { init(display); } - /** @hide */ - public static void setCompatibilityInfo(CompatibilityInfo compatInfo) { - if (compatInfo != null && (compatInfo.isScalingRequired() - || !compatInfo.supportsScreen())) { - sCompatibilityInfo = compatInfo; - } else { - sCompatibilityInfo = null; - } - } - /** * Returns the index of this display. This is currently undefined; do * not use. @@ -80,25 +72,29 @@ public class Display { native static int getDisplayCount(); /** - * Returns the raw size of the display, in pixels. Note that this - * should <em>not</em> generally be used for computing layouts, since - * a device will typically have screen decoration (such as a status bar) + * Gets the size of the display, in pixels. + * <p> + * Note that this value should <em>not</em> be used for computing layouts, + * since a device will typically have screen decoration (such as a status bar) * along the edges of the display that reduce the amount of application - * space available from the raw size returned here. This value is - * adjusted for you based on the current rotation of the display. + * space available from the size returned here. Layouts should instead use + * the window size. + * </p><p> + * The size is adjusted based on the current rotation of the display. + * </p><p> + * The size returned by this method does not necessarily represent the + * actual raw size (native resolution) of the display. The returned size may + * be adjusted to exclude certain system decor elements that are always visible. + * It may also be scaled to provide compatibility with older applications that + * were originally designed for smaller displays. + * </p> + * + * @param outSize A {@link Point} object to receive the size information. */ public void getSize(Point outSize) { getSizeInternal(outSize, true); } - /** - * Returns the raw size of the display, in pixels. Note that this - * should <em>not</em> generally be used for computing layouts, since - * a device will typically have screen decoration (such as a status bar) - * along the edges of the display that reduce the amount of application - * space available from the raw size returned here. This value is - * adjusted for you based on the current rotation of the display. - */ private void getSizeInternal(Point outSize, boolean doCompat) { try { IWindowManager wm = getWindowManager(); @@ -118,8 +114,8 @@ public class Display { } else { // This is just for boot-strapping, initializing the // system process before the window manager is up. - outSize.x = getRealWidth(); - outSize.y = getRealHeight(); + outSize.x = getRawWidth(); + outSize.y = getRawHeight(); } if (DEBUG_COMPAT && doCompat) Slog.v(TAG, "Returning display size: " + outSize); } catch (RemoteException e) { @@ -128,7 +124,10 @@ public class Display { } /** - * This is just easier for some parts of the framework. + * Gets the size of the display as a rectangle, in pixels. + * + * @param outSize A {@link Rect} object to receive the size information. + * @see #getSize(Point) */ public void getRectSize(Rect outSize) { synchronized (mTmpPoint) { @@ -182,14 +181,49 @@ public class Display { } } - /** @hide Returns the actual screen size, not including any decor. */ - native public int getRealWidth(); - /** @hide Returns the actual screen size, not including any decor. */ - native public int getRealHeight(); + /** + * Gets the real size of the display without subtracting any window decor or + * applying any compatibility scale factors. + * <p> + * The real size may be smaller than the raw size when the window manager + * is emulating a smaller display (using adb shell am display-size). + * </p><p> + * The size is adjusted based on the current rotation of the display. + * </p> + * @hide + */ + public void getRealSize(Point outSize) { + try { + IWindowManager wm = getWindowManager(); + if (wm != null) { + wm.getRealDisplaySize(outSize); + } else { + // This is just for boot-strapping, initializing the + // system process before the window manager is up. + outSize.x = getRawWidth(); + outSize.y = getRawHeight(); + } + } catch (RemoteException e) { + Slog.w("Display", "Unable to get real display size", e); + } + } - /** @hide special for when we are faking the screen size. */ + /** + * Gets the raw width of the display, in pixels. + * <p> + * The size is adjusted based on the current rotation of the display. + * </p> + * @hide + */ native public int getRawWidth(); - /** @hide special for when we are faking the screen size. */ + + /** + * Gets the raw height of the display, in pixels. + * <p> + * The size is adjusted based on the current rotation of the display. + * </p> + * @hide + */ native public int getRawHeight(); /** @@ -235,17 +269,24 @@ public class Display { } /** - * Initialize a DisplayMetrics object from this display's data. - * - * @param outMetrics + * Gets display metrics that describe the size and density of this display. + * <p> + * The size is adjusted based on the current rotation of the display. + * </p><p> + * The size returned by this method does not necessarily represent the + * actual raw size (native resolution) of the display. The returned size may + * be adjusted to exclude certain system decor elements that are always visible. + * It may also be scaled to provide compatibility with older applications that + * were originally designed for smaller displays. + * </p> + * + * @param outMetrics A {@link DisplayMetrics} object to receive the metrics. */ public void getMetrics(DisplayMetrics outMetrics) { synchronized (mTmpPoint) { getSizeInternal(mTmpPoint, false); - outMetrics.widthPixels = mTmpPoint.x; - outMetrics.heightPixels = mTmpPoint.y; + getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y); } - getNonSizeMetrics(outMetrics); CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded(); if (ci != null) { @@ -257,22 +298,44 @@ public class Display { } /** - * Initialize a DisplayMetrics object from this display's data. - * - * @param outMetrics + * Gets display metrics based on the real size of this display. * @hide */ public void getRealMetrics(DisplayMetrics outMetrics) { - outMetrics.widthPixels = getRealWidth(); - outMetrics.heightPixels = getRealHeight(); - getNonSizeMetrics(outMetrics); + synchronized (mTmpPoint) { + getRealSize(mTmpPoint); + getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y); + } + } + + /** + * If the display is mirrored to an external HDMI display, returns the + * width of that display. + * @hide + */ + public int getRawExternalWidth() { + return 1280; + } + + /** + * If the display is mirrored to an external HDMI display, returns the + * height of that display. + * @hide + */ + public int getRawExternalHeight() { + return 720; } - private void getNonSizeMetrics(DisplayMetrics outMetrics) { + /** + * Gets display metrics based on an explicit assumed display size. + * @hide + */ + public void getMetricsWithSize(DisplayMetrics outMetrics, + int width, int height) { outMetrics.densityDpi = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f); - outMetrics.noncompatWidthPixels = outMetrics.widthPixels; - outMetrics.noncompatHeightPixels = outMetrics.heightPixels; + outMetrics.noncompatWidthPixels = outMetrics.widthPixels = width; + outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height; outMetrics.density = outMetrics.noncompatDensity = mDensity; outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density; @@ -315,8 +378,6 @@ public class Display { private static boolean sInitialized = false; private static IWindowManager sWindowManager; - private static volatile CompatibilityInfo sCompatibilityInfo; - /** * Returns a display object which uses the metric's width/height instead. * @hide diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index f4c0249..8f4ece0 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -54,4 +54,11 @@ public abstract class DisplayList { * @return boolean true if the display list is able to be replayed, false otherwise. */ abstract boolean isValid(); + + /** + * Return the amount of memory used by this display list. + * + * @return The size of this display list in bytes + */ + abstract int getSize(); } diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index d561484..a7fe95d 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -277,14 +277,25 @@ class GLES20Canvas extends HardwareCanvas { /////////////////////////////////////////////////////////////////////////// /** + * Must match Caches::FlushMode values + * + * @see #flushCaches(int) + */ + public static final int FLUSH_CACHES_LAYERS = 0; + + /** + * Must match Caches::FlushMode values + * * @see #flushCaches(int) */ - public static final int FLUSH_CACHES_MODERATE = 0; + public static final int FLUSH_CACHES_MODERATE = 1; /** + * Must match Caches::FlushMode values + * * @see #flushCaches(int) */ - public static final int FLUSH_CACHES_FULL = 1; + public static final int FLUSH_CACHES_FULL = 2; /** * Flush caches to reclaim as much memory as possible. The amount of memory @@ -319,6 +330,12 @@ class GLES20Canvas extends HardwareCanvas { private static native void nDestroyDisplayList(int displayList); + static int getDisplayListSize(int displayList) { + return nGetDisplayListSize(displayList); + } + + private static native int nGetDisplayListSize(int displayList); + @Override public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) { return nDrawDisplayList(mRenderer, diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java index 9e649ce..4ca5e98 100644 --- a/core/java/android/view/GLES20DisplayList.java +++ b/core/java/android/view/GLES20DisplayList.java @@ -82,6 +82,12 @@ class GLES20DisplayList extends DisplayList { } } + @Override + int getSize() { + if (mFinalizer == null) return 0; + return GLES20Canvas.getDisplayListSize(mFinalizer.mNativeDisplayList); + } + private static class DisplayListFinalizer { final int mNativeDisplayList; diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java index 078222b..c987f48 100644 --- a/core/java/android/view/GLES20RecordingCanvas.java +++ b/core/java/android/view/GLES20RecordingCanvas.java @@ -38,7 +38,7 @@ import android.util.Pools; class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> { // The recording canvas pool should be large enough to handle a deeply nested // view hierarchy because display lists are generated recursively. - private static final int POOL_LIMIT = 50; + private static final int POOL_LIMIT = 25; private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool( Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() { diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index d2476af..4e4923b 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -140,6 +140,13 @@ public abstract class HardwareRenderer { abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException; /** + * Destoys the layers used by the specified view hierarchy. + * + * @param view The root of the view hierarchy + */ + abstract void destroyLayers(View view); + + /** * This method should be invoked whenever the current hardware renderer * context should be reset. */ @@ -622,18 +629,8 @@ public abstract class HardwareRenderer { + "from multiple threads"); } - /* - * The window size has changed, so we need to create a new - * surface. - */ - if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) { - /* - * Unbind and destroy the old EGL surface, if - * there is one. - */ - sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - sEgl.eglDestroySurface(sEglDisplay, mEglSurface); - } + // In case we need to destroy an existing surface + destroySurface(); // Create an EGL surface we can render into. mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null); @@ -693,15 +690,21 @@ public abstract class HardwareRenderer { mDestroyed = true; - sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - sEgl.eglDestroySurface(sEglDisplay, mEglSurface); + destroySurface(); - mEglSurface = null; mGl = null; setEnabled(false); } + void destroySurface() { + if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) { + sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + sEgl.eglDestroySurface(sEglDisplay, mEglSurface); + mEglSurface = null; + } + } + @Override void invalidate() { // Cancels any existing buffer to ensure we'll get a buffer @@ -921,6 +924,36 @@ public abstract class HardwareRenderer { return ((GLES20TextureLayer) layer).getSurfaceTexture(); } + @Override + void destroyLayers(View view) { + if (view != null && isEnabled()) { + checkCurrent(); + destroyHardwareLayer(view); + GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); + } + } + + private void destroyHardwareLayer(View view) { + if (view.destroyLayer()) { + view.invalidate(true); + } + if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup) view; + + int count = group.getChildCount(); + for (int i = 0; i < count; i++) { + destroyHardwareLayer(group.getChildAt(i)); + } + } + } + + static HardwareRenderer create(boolean translucent) { + if (GLES20Canvas.isAvailable()) { + return new Gl20Renderer(translucent); + } + return null; + } + static void trimMemory(int level) { if (sEgl == null || sEglConfig == null) return; @@ -950,12 +983,5 @@ public abstract class HardwareRenderer { break; } } - - static HardwareRenderer create(boolean translucent) { - if (GLES20Canvas.isAvailable()) { - return new Gl20Renderer(translucent); - } - return null; - } } } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index ad17edf..81cd798 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -55,6 +55,7 @@ interface IWindowManager boolean inputMethodClientHasFocus(IInputMethodClient client); void getDisplaySize(out Point size); + void getRealDisplaySize(out Point size); int getMaximumSizeDimension(); void setForcedDisplaySize(int longDimen, int shortDimen); diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 88f59d4..da5c7b2 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -1123,7 +1123,10 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** - * Button constant: Primary button (left mouse button, stylus tip). + * Button constant: Primary button (left mouse button). + * + * This button constant is not set in response to simple touches with a finger + * or stylus tip. The user must actually push a button. * * @see #getButtonState */ @@ -1215,55 +1218,32 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int TOOL_TYPE_UNKNOWN = 0; /** - * Tool type constant: The tool is a finger directly touching the display. - * - * This is a <em>direct</em> positioning tool. + * Tool type constant: The tool is a finger. * * @see #getToolType */ public static final int TOOL_TYPE_FINGER = 1; /** - * Tool type constant: The tool is a stylus directly touching the display - * or hovering slightly above it. - * - * This is a <em>direct</em> positioning tool. + * Tool type constant: The tool is a stylus. * * @see #getToolType */ public static final int TOOL_TYPE_STYLUS = 2; /** - * Tool type constant: The tool is a mouse or trackpad that translates - * relative motions into cursor movements on the display. - * - * This is an <em>indirect</em> positioning tool. + * Tool type constant: The tool is a mouse or trackpad. * * @see #getToolType */ public static final int TOOL_TYPE_MOUSE = 3; /** - * Tool type constant: The tool is a finger on a touch pad that is not - * directly attached to the display. Finger movements on the touch pad - * may be translated into touches on the display, possibly with visual feedback. - * - * This is an <em>indirect</em> positioning tool. - * - * @see #getToolType - */ - public static final int TOOL_TYPE_INDIRECT_FINGER = 4; - - /** - * Tool type constant: The tool is a stylus on a digitizer tablet that is not - * attached to the display. Stylus movements on the digitizer may be translated - * into touches on the display, possibly with visual feedback. - * - * This is an <em>indirect</em> positioning tool. + * Tool type constant: The tool is an eraser or a stylus being used in an inverted posture. * * @see #getToolType */ - public static final int TOOL_TYPE_INDIRECT_STYLUS = 5; + public static final int TOOL_TYPE_ERASER = 4; // NOTE: If you add a new tool type here you must also add it to: // native/include/android/input.h @@ -1276,8 +1256,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { names.append(TOOL_TYPE_FINGER, "TOOL_TYPE_FINGER"); names.append(TOOL_TYPE_STYLUS, "TOOL_TYPE_STYLUS"); names.append(TOOL_TYPE_MOUSE, "TOOL_TYPE_MOUSE"); - names.append(TOOL_TYPE_INDIRECT_FINGER, "TOOL_TYPE_INDIRECT_FINGER"); - names.append(TOOL_TYPE_INDIRECT_STYLUS, "TOOL_TYPE_INDIRECT_STYLUS"); + names.append(TOOL_TYPE_ERASER, "TOOL_TYPE_ERASER"); } // Private value for history pos that obtains the current sample. diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 2213188..296e6be 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -672,19 +672,23 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit private static final int FITS_SYSTEM_WINDOWS = 0x00000002; /** - * This view is visible. Use with {@link #setVisibility(int)}. + * This view is visible. + * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code + * android:visibility}. */ public static final int VISIBLE = 0x00000000; /** * This view is invisible, but it still takes up space for layout purposes. - * Use with {@link #setVisibility(int)}. + * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code + * android:visibility}. */ public static final int INVISIBLE = 0x00000004; /** * This view is invisible, and it doesn't take any space for layout - * purposes. Use with {@link #setVisibility(int)}. + * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code + * android:visibility}. */ public static final int GONE = 0x00000008; @@ -2294,8 +2298,8 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit private Bitmap mDrawingCache; private Bitmap mUnscaledDrawingCache; - private DisplayList mDisplayList; private HardwareLayer mHardwareLayer; + DisplayList mDisplayList; /** * When this view has focus and the next focus is {@link #FOCUS_LEFT}, @@ -9226,10 +9230,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit destroyDrawingCache(); - if (mHardwareLayer != null) { - mHardwareLayer.destroy(); - mHardwareLayer = null; - } + destroyLayer(); if (mDisplayList != null) { mDisplayList.invalidate(); @@ -9601,21 +9602,10 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit // Destroy any previous software drawing cache if needed switch (mLayerType) { case LAYER_TYPE_HARDWARE: - if (mHardwareLayer != null) { - mHardwareLayer.destroy(); - mHardwareLayer = null; - } + destroyLayer(); // fall through - unaccelerated views may use software layer mechanism instead case LAYER_TYPE_SOFTWARE: - if (mDrawingCache != null) { - mDrawingCache.recycle(); - mDrawingCache = null; - } - - if (mUnscaledDrawingCache != null) { - mUnscaledDrawingCache.recycle(); - mUnscaledDrawingCache = null; - } + destroyDrawingCache(); break; default: break; @@ -9741,6 +9731,15 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit return mHardwareLayer; } + boolean destroyLayer() { + if (mHardwareLayer != null) { + mHardwareLayer.destroy(); + mHardwareLayer = null; + return true; + } + return false; + } + /** * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 4acf48c..96e550e 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -420,7 +420,7 @@ public class ViewDebug { * * @hide */ - public static long getViewAncestorInstanceCount() { + public static long getViewRootImplCount() { return Debug.countInstancesOfClass(ViewRootImpl.class); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 35a40fc..9460fe5 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -80,6 +80,7 @@ import com.android.internal.view.RootViewSurfaceTaker; import java.io.IOException; import java.io.OutputStream; +import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -235,7 +236,6 @@ public final class ViewRootImpl extends Handler implements ViewParent, final Configuration mLastConfiguration = new Configuration(); final Configuration mPendingConfiguration = new Configuration(); - class ResizedInfo { Rect coveredInsets; Rect visibleInsets; @@ -541,6 +541,29 @@ public final class ViewRootImpl extends Handler implements ViewParent, } } + private void destroyHardwareResources() { + if (mAttachInfo.mHardwareRenderer != null) { + if (mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.destroyLayers(mView); + } + mAttachInfo.mHardwareRenderer.destroy(false); + } + } + + void destroyHardwareLayers() { + if (mThread != Thread.currentThread()) { + if (mAttachInfo.mHardwareRenderer != null && + mAttachInfo.mHardwareRenderer.isEnabled()) { + HardwareRenderer.trimMemory(ComponentCallbacks.TRIM_MEMORY_MODERATE); + } + } else { + if (mAttachInfo.mHardwareRenderer != null && + mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.destroyLayers(mView); + } + } + } + private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { mAttachInfo.mHardwareAccelerated = false; mAttachInfo.mHardwareAccelerationRequested = false; @@ -825,8 +848,10 @@ public final class ViewRootImpl extends Handler implements ViewParent, if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) { // NOTE -- system code, won't try to do compat mode. Display disp = WindowManagerImpl.getDefault().getDefaultDisplay(); - desiredWindowWidth = disp.getRealWidth(); - desiredWindowHeight = disp.getRealHeight(); + Point size = new Point(); + disp.getRealSize(size); + desiredWindowWidth = size.x; + desiredWindowHeight = size.y; } else { DisplayMetrics packageMetrics = mView.getContext().getResources().getDisplayMetrics(); @@ -869,9 +894,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, attachInfo.mWindowVisibility = viewVisibility; host.dispatchWindowVisibilityChanged(viewVisibility); if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { - if (mAttachInfo.mHardwareRenderer != null) { - mAttachInfo.mHardwareRenderer.destroy(false); - } + destroyHardwareResources(); } if (viewVisibility == View.GONE) { // After making a window gone, we will count it as being @@ -980,8 +1003,10 @@ public final class ViewRootImpl extends Handler implements ViewParent, if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) { // NOTE -- system code, won't try to do compat mode. Display disp = WindowManagerImpl.getDefault().getDefaultDisplay(); - desiredWindowWidth = disp.getRealWidth(); - desiredWindowHeight = disp.getRealHeight(); + Point size = new Point(); + disp.getRealSize(size); + desiredWindowWidth = size.x; + desiredWindowHeight = size.y; } else { DisplayMetrics packageMetrics = res.getDisplayMetrics(); desiredWindowWidth = packageMetrics.widthPixels; @@ -3485,6 +3510,31 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void debug() { mView.debug(); } + + public void dumpGfxInfo(PrintWriter pw, int[] info) { + if (mView != null) { + getGfxInfo(mView, info); + } else { + info[0] = info[1] = 0; + } + } + + private void getGfxInfo(View view, int[] info) { + DisplayList displayList = view.mDisplayList; + info[0]++; + if (displayList != null) { + info[1] += displayList.getSize(); + } + + if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup) view; + + int count = group.getChildCount(); + for (int i = 0; i < count; i++) { + getGfxInfo(group.getChildAt(i), info); + } + } + } public void die(boolean immediate) { if (immediate) { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index a451bb5..5ef4f3e 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -24,6 +24,9 @@ import android.util.AndroidRuntimeException; import android.util.Log; import android.view.inputmethod.InputMethodManager; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.PrintWriter; import java.util.HashMap; final class WindowLeaked extends AndroidRuntimeException { @@ -392,7 +395,7 @@ public class WindowManagerImpl implements WindowManager { leak.setStackTrace(root.getLocation().getStackTrace()); Log.e("WindowManager", leak.getMessage(), leak); } - + removeViewLocked(i); i--; count--; @@ -410,6 +413,59 @@ public class WindowManagerImpl implements WindowManager { } } + /** + * @hide + */ + public void trimLocalMemory() { + synchronized (this) { + if (mViews == null) return; + int count = mViews.length; + for (int i = 0; i < count; i++) { + mRoots[i].destroyHardwareLayers(); + } + } + } + + /** + * @hide + */ + public void dumpGfxInfo(FileDescriptor fd) { + FileOutputStream fout = new FileOutputStream(fd); + PrintWriter pw = new PrintWriter(fout); + try { + synchronized (this) { + if (mViews != null) { + pw.println("View hierarchy:"); + + final int count = mViews.length; + + int viewsCount = 0; + int displayListsSize = 0; + int[] info = new int[2]; + + for (int i = 0; i < count; i++) { + ViewRootImpl root = mRoots[i]; + root.dumpGfxInfo(pw, info); + + String name = root.getClass().getName() + '@' + + Integer.toHexString(hashCode()); + pw.printf(" %s: %d views, %.2f kB (display lists)\n", + name, info[0], info[1] / 1024.0f); + + viewsCount += info[0]; + displayListsSize += info[1]; + } + + pw.printf("\nTotal ViewRootImpl: %d\n", count); + pw.printf("Total Views: %d\n", viewsCount); + pw.printf("Total DisplayList: %.2f kB\n\n", displayListsSize / 1024.0f); + } + } + } finally { + pw.flush(); + } + } + public void setStoppedState(IBinder token, boolean stopped) { synchronized (this) { if (mViews == null) diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java index 3cb5e24..a21d3ee 100644 --- a/core/java/android/webkit/DebugFlags.java +++ b/core/java/android/webkit/DebugFlags.java @@ -47,7 +47,7 @@ class DebugFlags { public static final boolean WEB_VIEW_CORE = false; /* * Set to true to allow the WebTextView to draw on top of the web page in a - * different color so that you can see how the two line up. + * different color with no background so you can see how the two line up. */ public static final boolean DRAW_WEBTEXTVIEW = false; } diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java index d54230c..b8c4e22 100644 --- a/core/java/android/webkit/WebTextView.java +++ b/core/java/android/webkit/WebTextView.java @@ -25,7 +25,7 @@ import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.drawable.Drawable; +import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -87,7 +87,6 @@ import junit.framework.Assert; // Keep track of the text before the change so we know whether we actually // need to send down the DOM events. private String mPreChange; - private Drawable mBackground; // Variables for keeping track of the touch down, to send to the WebView // when a drag starts private float mDragStartX; @@ -190,6 +189,8 @@ import junit.framework.Assert; // that other applications that use embedded WebViews will properly // display the text in password textfields. setTextColor(DebugFlags.DRAW_WEBTEXTVIEW ? Color.RED : Color.BLACK); + setBackgroundDrawable(DebugFlags.DRAW_WEBTEXTVIEW ? null : new ColorDrawable(Color.WHITE)); + // This helps to align the text better with the text in the web page. setIncludeFontPadding(false); @@ -423,24 +424,6 @@ import junit.framework.Assert; // makeNewLayout does. super.makeNewLayout(w, hintWidth, boring, hintBoring, ellipsisWidth, bringIntoView); - - // For fields that do not draw, create a layout which is altered so that - // the text lines up. - if (DebugFlags.DRAW_WEBTEXTVIEW || willNotDraw()) { - float lineHeight = -1; - if (mWebView != null) { - float height = mWebView.nativeFocusCandidateLineHeight(); - if (height != -1) { - lineHeight = height * mWebView.getScale(); - } - } - CharSequence text = getText(); - // Copy from the existing Layout. - mLayout = new WebTextViewLayout(text, text, getPaint(), mLayout.getWidth(), - mLayout.getAlignment(), mLayout.getSpacingMultiplier(), - mLayout.getSpacingAdd(), false, null, ellipsisWidth, - lineHeight); - } lineUpScroll(); } @@ -491,51 +474,6 @@ import junit.framework.Assert; return connection; } - /** - * In general, TextView makes a call to InputMethodManager.updateSelection - * in onDraw. However, in the general case of WebTextView, we do not draw. - * This method is called by WebView.onDraw to take care of the part that - * needs to be called. - */ - /* package */ void onDrawSubstitute() { - if (!willNotDraw()) { - // If the WebTextView is set to draw, such as in the case of a - // password, onDraw calls updateSelection(), so this code path is - // unnecessary. - return; - } - // This code is copied from TextView.onDraw(). That code does not get - // executed, however, because the WebTextView does not draw, allowing - // webkit's drawing to show through. - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null && imm.isActive(this)) { - Spannable sp = (Spannable) getText(); - int selStart = Selection.getSelectionStart(sp); - int selEnd = Selection.getSelectionEnd(sp); - int candStart = EditableInputConnection.getComposingSpanStart(sp); - int candEnd = EditableInputConnection.getComposingSpanEnd(sp); - imm.updateSelection(this, selStart, selEnd, candStart, candEnd); - } - } - - @Override - protected void onDraw(Canvas canvas) { - // onDraw should only be called for password fields. If WebTextView is - // still drawing, but is no longer corresponding to a password field, - // remove it. - if (!DebugFlags.DRAW_WEBTEXTVIEW && (mWebView == null - || !mWebView.nativeFocusCandidateIsPassword() - || !isSameTextField(mWebView.nativeFocusCandidatePointer()))) { - // Although calling remove() would seem to make more sense here, - // changing it to not be a password field will make it not draw. - // Other code will make sure that it is removed completely, but this - // way the user will not see it. - setInPassword(false); - } else { - super.onDraw(canvas); - } - } - @Override public void onEditorAction(int actionCode) { switch (actionCode) { @@ -928,102 +866,6 @@ import junit.framework.Assert; if (mWebView != null) mWebView.incrementTextGeneration(); } - /** - * Determine whether to use the system-wide password disguising method, - * or to use none. - * @param inPassword True if the textfield is a password field. - */ - /* package */ void setInPassword(boolean inPassword) { - if (inPassword) { - setInputType(InputType.TYPE_CLASS_TEXT | EditorInfo. - TYPE_TEXT_VARIATION_WEB_PASSWORD); - createBackground(); - } - // For password fields, draw the WebTextView. For others, just show - // webkit's drawing. - if (!DebugFlags.DRAW_WEBTEXTVIEW) { - setWillNotDraw(!inPassword); - } - setBackgroundDrawable(inPassword ? mBackground : null); - } - - /** - * Private class used for the background of a password textfield. - */ - private static class OutlineDrawable extends Drawable { - private Paint mBackgroundPaint; - private Paint mOutlinePaint; - private float[] mLines; - public OutlineDrawable() { - mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBackgroundPaint.setColor(Color.WHITE); - - mOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mOutlinePaint.setColor(Color.BLACK); - mOutlinePaint.setStyle(Paint.Style.STROKE); - - mLines = new float[16]; - } - @Override - public void setBounds(int left, int top, int right, int bottom) { - super.setBounds(left, top, right, bottom); - bottom--; - right -= 2; - // Top line - mLines[0] = left; - mLines[1] = top + 1; - mLines[2] = right; - mLines[3] = top + 1; - // Right line - mLines[4] = right; - mLines[5] = top; - mLines[6] = right; - mLines[7] = bottom; - // Bottom line - mLines[8] = left; - mLines[9] = bottom; - mLines[10] = right; - mLines[11] = bottom; - // Left line - mLines[12] = left + 1; - mLines[13] = top; - mLines[14] = left + 1; - mLines[15] = bottom; - } - @Override - public void draw(Canvas canvas) { - // Draw the background. - canvas.drawRect(getBounds(), mBackgroundPaint); - // Draw the outline. - canvas.drawLines(mLines, mOutlinePaint); - } - // Always want it to be opaque. - @Override - public int getOpacity() { - return PixelFormat.OPAQUE; - } - // These are needed because they are abstract in Drawable. - @Override - public void setAlpha(int alpha) { } - @Override - public void setColorFilter(ColorFilter cf) { } - } - - /** - * Create a background for the WebTextView and set up the paint for drawing - * the text. This way, we can see the password transformation of the - * system, which (optionally) shows the actual text before changing to dots. - * The background is necessary to hide the webkit-drawn text beneath. - */ - private void createBackground() { - if (mBackground != null) { - return; - } - mBackground = new OutlineDrawable(); - - setGravity(Gravity.CENTER_VERTICAL); - } - @Override public void setInputType(int type) { mFromSetInputType = true; @@ -1072,7 +914,8 @@ import junit.framework.Assert; lp.height = height; } if (getParent() == null) { - mWebView.addView(this, lp); + // Insert the view so that it's drawn first (at index 0) + mWebView.addView(this, 0, lp); } else { setLayoutParams(lp); } @@ -1145,7 +988,6 @@ import junit.framework.Assert; /* package */ void setType(int type) { if (mWebView == null) return; boolean single = true; - boolean inPassword = false; int maxLength = -1; int inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT; @@ -1167,7 +1009,7 @@ import junit.framework.Assert; imeOptions |= EditorInfo.IME_ACTION_NONE; break; case PASSWORD: - inPassword = true; + inputType |= EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD; imeOptions |= EditorInfo.IME_ACTION_GO; break; case SEARCH: @@ -1219,7 +1061,7 @@ import junit.framework.Assert; setHorizontallyScrolling(single); setInputType(inputType); setImeOptions(imeOptions); - setInPassword(inPassword); + setVisibility(VISIBLE); AutoCompleteAdapter adapter = null; setAdapterCustom(adapter); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index e24ab58..a935a67 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -4068,9 +4068,6 @@ public class WebView extends AbsoluteLayout if (AUTO_REDRAW_HACK && mAutoRedraw) { invalidate(); } - if (inEditingMode()) { - mWebTextView.onDrawSubstitute(); - } mWebViewCore.signalRepaintDone(); if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas)) { @@ -4287,18 +4284,18 @@ public class WebView extends AbsoluteLayout private void onZoomAnimationStart() { // If it is in password mode, turn it off so it does not draw misplaced. - if (inEditingMode() && nativeFocusCandidateIsPassword()) { - mWebTextView.setInPassword(false); + if (inEditingMode()) { + mWebTextView.setVisibility(INVISIBLE); } } private void onZoomAnimationEnd() { // adjust the edit text view if needed - if (inEditingMode() && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN) - && nativeFocusCandidateIsPassword()) { + if (inEditingMode() + && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)) { // If it is a password field, start drawing the WebTextView once // again. - mWebTextView.setInPassword(true); + mWebTextView.setVisibility(VISIBLE); } } @@ -4593,37 +4590,23 @@ public class WebView extends AbsoluteLayout } String text = nativeFocusCandidateText(); int nodePointer = nativeFocusCandidatePointer(); - if (alreadyThere && mWebTextView.isSameTextField(nodePointer)) { - // It is possible that we have the same textfield, but it has moved, - // i.e. In the case of opening/closing the screen. - // In that case, we need to set the dimensions, but not the other - // aspects. - // If the text has been changed by webkit, update it. However, if - // there has been more UI text input, ignore it. We will receive - // another update when that text is recognized. - if (text != null && !text.equals(mWebTextView.getText().toString()) - && nativeTextGeneration() == mTextGeneration) { - mWebTextView.setTextAndKeepSelection(text); - } - } else { - mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ? - Gravity.RIGHT : Gravity.NO_GRAVITY); - // This needs to be called before setType, which may call - // requestFormData, and it needs to have the correct nodePointer. - mWebTextView.setNodePointer(nodePointer); - mWebTextView.setType(nativeFocusCandidateType()); - updateWebTextViewPadding(); - if (null == text) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "rebuildWebTextView null == text"); - } - text = ""; - } - mWebTextView.setTextAndKeepSelection(text); - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null && imm.isActive(mWebTextView)) { - imm.restartInput(mWebTextView); + mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ? + Gravity.RIGHT : Gravity.NO_GRAVITY); + // This needs to be called before setType, which may call + // requestFormData, and it needs to have the correct nodePointer. + mWebTextView.setNodePointer(nodePointer); + mWebTextView.setType(nativeFocusCandidateType()); + updateWebTextViewPadding(); + if (null == text) { + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "rebuildWebTextView null == text"); } + text = ""; + } + mWebTextView.setTextAndKeepSelection(text); + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null && imm.isActive(mWebTextView)) { + imm.restartInput(mWebTextView); } if (isFocused()) { mWebTextView.requestFocus(); @@ -8120,19 +8103,7 @@ public class WebView extends AbsoluteLayout // and representing the same node as the pointer. if (inEditingMode() && mWebTextView.isSameTextField(msg.arg1)) { - if (msg.getData().getBoolean("password")) { - Spannable text = (Spannable) mWebTextView.getText(); - int start = Selection.getSelectionStart(text); - int end = Selection.getSelectionEnd(text); - mWebTextView.setInPassword(true); - // Restore the selection, which may have been - // ruined by setInPassword. - Spannable pword = - (Spannable) mWebTextView.getText(); - Selection.setSelection(pword, start, end); - // If the text entry has created more events, ignore - // this one. - } else if (msg.arg2 == mTextGeneration) { + if (msg.arg2 == mTextGeneration) { String text = (String) msg.obj; if (null == text) { text = ""; diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index 5eba1a0..0b0b812 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -34,12 +34,17 @@ import android.widget.RemoteViews.RemoteView; /** * FrameLayout is designed to block out an area on the screen to display - * a single item. You can add multiple children to a FrameLayout and control their - * position within the FrameLayout using {@link android.widget.FrameLayout.LayoutParams#gravity}. - * Children are drawn in a stack, with the most recently added child on top. - * The size of the frame layout is the size of its largest child (plus padding), visible - * or not (if the FrameLayout's parent permits). Views that are GONE are used for sizing - * only if {@link #setMeasureAllChildren(boolean) setMeasureAllChildren()} + * a single item. Generally, FrameLayout should be used to hold a single child view, because it can + * be difficult to organize child views in a way that's scalable to different screen sizes without + * the children overlapping each other. You can, however, add multiple children to a FrameLayout + * and control their position within the FrameLayout by assigning gravity to each child, using the + * <a href="FrameLayout.LayoutParams.html#attr_android:layout_gravity">{@code + * android:layout_gravity}</a> attribute. + * <p>Child views are drawn in a stack, with the most recently added child on top. + * The size of the FrameLayout is the size of its largest child (plus padding), visible + * or not (if the FrameLayout's parent permits). Views that are {@link android.view.View#GONE} are + * used for sizing + * only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()} * is set to true. * * @attr ref android.R.styleable#FrameLayout_foreground diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 55b73df..91b19ed 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -221,6 +221,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { mCloseButton.setOnClickListener(mOnClickListener); mSubmitButton.setOnClickListener(mOnClickListener); mVoiceButton.setOnClickListener(mOnClickListener); + mQueryTextView.setOnClickListener(mOnClickListener); mQueryTextView.addTextChangedListener(mTextWatcher); mQueryTextView.setOnEditorActionListener(mOnEditorActionListener); @@ -319,7 +320,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { // If it is not iconified, then give the focus to the text field if (!isIconified()) { boolean result = mQueryTextView.requestFocus(direction, previouslyFocusedRect); - if (result) updateViewsVisibility(false); + if (result) { + updateViewsVisibility(false); + } return result; } else { return super.requestFocus(direction, previouslyFocusedRect); @@ -330,9 +333,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { @Override public void clearFocus() { mClearingFocus = true; + setImeVisibility(false); super.clearFocus(); mQueryTextView.clearFocus(); - setImeVisibility(false); mClearingFocus = false; } @@ -681,6 +684,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { onSubmitQuery(); } else if (v == mVoiceButton) { onVoiceClicked(); + } else if (v == mQueryTextView) { + forceSuggestionQuery(); } } }; @@ -1029,6 +1034,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { void onTextFocusChanged() { updateViewsVisibility(isIconified()); updateFocusedState(mQueryTextView.hasFocus()); + if (mQueryTextView.hasFocus()) { + forceSuggestionQuery(); + } } @Override @@ -1041,8 +1049,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { */ @Override public void onActionViewCollapsed() { + clearFocus(); + updateViewsVisibility(true); mQueryTextView.setText(""); - setIconified(true); mExpandedInActionView = false; } @@ -1376,6 +1385,11 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { } } + private void forceSuggestionQuery() { + mQueryTextView.doBeforeTextChanged(); + mQueryTextView.doAfterTextChanged(); + } + static boolean isLandscapeMode(Context context) { return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 9ae7def..1531946 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -1,22 +1,9 @@ package com.android.internal.content; -import android.content.pm.PackageManager; import android.os.Build; -import android.os.FileUtils; -import android.os.SystemProperties; -import android.util.Log; -import android.util.Pair; import android.util.Slog; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.LinkedList; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; /** * Native libraries helper. @@ -28,270 +15,22 @@ public class NativeLibraryHelper { private static final boolean DEBUG_NATIVE = false; - /* - * The following constants are returned by listPackageSharedLibsForAbiLI - * to indicate if native shared libraries were found in the package. - * Values are: - * PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed - * PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package - * PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found - * in package (and not installed) - * - */ - private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0; - private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1; - private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2; + private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2); - // Directory in the APK that holds all the native shared libraries. - private static final String APK_LIB = "lib/"; - private static final int APK_LIB_LENGTH = APK_LIB.length(); - - // Prefix that native shared libraries must have. - private static final String LIB_PREFIX = "lib"; - private static final int LIB_PREFIX_LENGTH = LIB_PREFIX.length(); - - // Suffix that the native shared libraries must have. - private static final String LIB_SUFFIX = ".so"; - private static final int LIB_SUFFIX_LENGTH = LIB_SUFFIX.length(); - - // Name of the GDB binary. - private static final String GDBSERVER = "gdbserver"; - - // the minimum length of a valid native shared library of the form - // lib/<something>/lib<name>.so. - private static final int MIN_ENTRY_LENGTH = APK_LIB_LENGTH + 2 + LIB_PREFIX_LENGTH + 1 - + LIB_SUFFIX_LENGTH; - - /* - * Find all files of the form lib/<cpuAbi>/lib<name>.so in the .apk - * and add them to a list to be installed later. - * - * NOTE: this method may throw an IOException if the library cannot - * be copied to its final destination, e.g. if there isn't enough - * room left on the data partition, or a ZipException if the package - * file is malformed. - */ - private static int listPackageSharedLibsForAbiLI(ZipFile zipFile, - String cpuAbi, List<Pair<ZipEntry, String>> libEntries) throws IOException, - ZipException { - final int cpuAbiLen = cpuAbi.length(); - boolean hasNativeLibraries = false; - boolean installedNativeLibraries = false; - - if (DEBUG_NATIVE) { - Slog.d(TAG, "Checking " + zipFile.getName() + " for shared libraries of CPU ABI type " - + cpuAbi); - } - - Enumeration<? extends ZipEntry> entries = zipFile.entries(); - - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - - // skip directories - if (entry.isDirectory()) { - continue; - } - String entryName = entry.getName(); - - /* - * Check that the entry looks like lib/<something>/lib<name>.so - * here, but don't check the ABI just yet. - * - * - must be sufficiently long - * - must end with LIB_SUFFIX, i.e. ".so" - * - must start with APK_LIB, i.e. "lib/" - */ - if (entryName.length() < MIN_ENTRY_LENGTH || !entryName.endsWith(LIB_SUFFIX) - || !entryName.startsWith(APK_LIB)) { - continue; - } - - // file name must start with LIB_PREFIX, i.e. "lib" - int lastSlash = entryName.lastIndexOf('/'); - - if (lastSlash < 0 - || !entryName.regionMatches(lastSlash + 1, LIB_PREFIX, 0, LIB_PREFIX_LENGTH)) { - continue; - } - - hasNativeLibraries = true; - - // check the cpuAbi now, between lib/ and /lib<name>.so - if (lastSlash != APK_LIB_LENGTH + cpuAbiLen - || !entryName.regionMatches(APK_LIB_LENGTH, cpuAbi, 0, cpuAbiLen)) - continue; - - /* - * Extract the library file name, ensure it doesn't contain - * weird characters. we're guaranteed here that it doesn't contain - * a directory separator though. - */ - String libFileName = entryName.substring(lastSlash+1); - if (!FileUtils.isFilenameSafe(new File(libFileName))) { - continue; - } - - installedNativeLibraries = true; - - if (DEBUG_NATIVE) { - Log.d(TAG, "Caching shared lib " + entry.getName()); - } - - libEntries.add(Pair.create(entry, libFileName)); - } - if (!hasNativeLibraries) - return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; - - if (!installedNativeLibraries) - return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH; - - return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; + public static long sumNativeBinariesLI(File apkFile) { + final String cpuAbi = Build.CPU_ABI; + final String cpuAbi2 = Build.CPU_ABI2; + return nativeSumNativeBinaries(apkFile.getPath(), cpuAbi, cpuAbi2); } - /* - * Find the gdbserver executable program in a package at - * lib/<cpuAbi>/gdbserver and add it to the list of binaries - * to be copied out later. - * - * Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success, - * or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise. - */ - private static int listPackageGdbServerLI(ZipFile zipFile, String cpuAbi, - List<Pair<ZipEntry, String>> nativeFiles) throws IOException, ZipException { - final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER; - - Enumeration<? extends ZipEntry> entries = zipFile.entries(); - - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - // skip directories - if (entry.isDirectory()) { - continue; - } - String entryName = entry.getName(); - - if (!entryName.equals(apkGdbServerPath)) { - continue; - } - - if (false) { - Log.d(TAG, "Found gdbserver: " + entry.getName()); - } + private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath, + String cpuAbi, String cpuAbi2); - final String installGdbServerPath = GDBSERVER; - nativeFiles.add(Pair.create(entry, installGdbServerPath)); - - return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; - } - return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; - } - - /* - * Examine shared libraries stored in the APK as - * lib/<cpuAbi>/lib<name>.so and add them to a list to be copied - * later. - * - * This function will first try the main CPU ABI defined by Build.CPU_ABI - * (which corresponds to ro.product.cpu.abi), and also try an alternate - * one if ro.product.cpu.abi2 is defined. - */ - public static int listPackageNativeBinariesLI(ZipFile zipFile, - List<Pair<ZipEntry, String>> nativeFiles) throws ZipException, IOException { - String cpuAbi = Build.CPU_ABI; - - int result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi, nativeFiles); - - /* - * Some architectures are capable of supporting several CPU ABIs - * for example, 'armeabi-v7a' also supports 'armeabi' native code - * this is indicated by the definition of the ro.product.cpu.abi2 - * system property. - * - * only scan the package twice in case of ABI mismatch - */ - if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { - final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2", null); - if (cpuAbi2 != null) { - result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi2, nativeFiles); - } - - if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { - Slog.w(TAG, "Native ABI mismatch from package file"); - return PackageManager.INSTALL_FAILED_INVALID_APK; - } - - if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { - cpuAbi = cpuAbi2; - } - } - - /* - * Debuggable packages may have gdbserver embedded, so add it to - * the list to the list of items to be extracted (as lib/gdbserver) - * into the application's native library directory later. - */ - if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { - listPackageGdbServerLI(zipFile, cpuAbi, nativeFiles); - } - return PackageManager.INSTALL_SUCCEEDED; - } - - public static int copyNativeBinariesLI(File scanFile, File sharedLibraryDir) { - /* - * Check all the native files that need to be copied and add - * that to the container size. - */ - ZipFile zipFile; - try { - zipFile = new ZipFile(scanFile); - - List<Pair<ZipEntry, String>> nativeFiles = new LinkedList<Pair<ZipEntry, String>>(); - - NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); - - final int N = nativeFiles.size(); - - for (int i = 0; i < N; i++) { - final Pair<ZipEntry, String> entry = nativeFiles.get(i); - - File destFile = new File(sharedLibraryDir, entry.second); - copyNativeBinaryLI(zipFile, entry.first, sharedLibraryDir, destFile); - } - zipFile.close(); - } catch (ZipException e) { - Slog.w(TAG, "Failed to extract data from package file", e); - return PackageManager.INSTALL_FAILED_INVALID_APK; - } catch (IOException e) { - Slog.w(TAG, "Failed to cache package shared libs", e); - return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - } - - return PackageManager.INSTALL_SUCCEEDED; - } - - private static void copyNativeBinaryLI(ZipFile zipFile, ZipEntry entry, - File binaryDir, File binaryFile) throws IOException { - InputStream inputStream = zipFile.getInputStream(entry); - try { - File tempFile = File.createTempFile("tmp", "tmp", binaryDir); - String tempFilePath = tempFile.getPath(); - // XXX package manager can't change owner, so the executable files for - // now need to be left as world readable and owned by the system. - if (!FileUtils.copyToFile(inputStream, tempFile) - || !tempFile.setLastModified(entry.getTime()) - || FileUtils.setPermissions(tempFilePath, FileUtils.S_IRUSR | FileUtils.S_IWUSR - | FileUtils.S_IRGRP | FileUtils.S_IXUSR | FileUtils.S_IXGRP - | FileUtils.S_IXOTH | FileUtils.S_IROTH, -1, -1) != 0 - || !tempFile.renameTo(binaryFile)) { - // Failed to properly write file. - tempFile.delete(); - throw new IOException("Couldn't create cached binary " + binaryFile + " in " - + binaryDir); - } - } finally { - inputStream.close(); - } + public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) { + final String cpuAbi = Build.CPU_ABI; + final String cpuAbi2 = Build.CPU_ABI2; + return nativeCopyNativeBinaries(apkFile.getPath(), sharedLibraryDir.getPath(), cpuAbi, + cpuAbi2); } // Convenience method to call removeNativeBinariesFromDirLI(File) diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java index bf2965b..bff621c 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuView.java +++ b/core/java/com/android/internal/view/menu/ActionMenuView.java @@ -36,8 +36,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo private boolean mReserveOverflow; private ActionMenuPresenter mPresenter; - private boolean mUpdateContentsBeforeMeasure; private boolean mFormatItems; + private int mFormatItemsWidth; private int mMinCellSize; private int mMeasuredExtraWidth; @@ -71,19 +71,21 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo } @Override - public void requestLayout() { - // Layout can influence how many action items fit. - mUpdateContentsBeforeMeasure = true; - super.requestLayout(); - } - - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // If we've been given an exact size to match, apply special formatting during layout. + final boolean wasFormatted = mFormatItems; mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY; - if (mUpdateContentsBeforeMeasure && mMenu != null) { + + if (wasFormatted != mFormatItems) { + mFormatItemsWidth = 0; // Reset this when switching modes + } + + // Special formatting can change whether items can fit as action buttons. + // Kick the menu and update presenters when this changes. + final int widthSize = MeasureSpec.getMode(widthMeasureSpec); + if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) { + mFormatItemsWidth = widthSize; mMenu.onItemsChanged(true); - mUpdateContentsBeforeMeasure = false; } if (mFormatItems) { diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index 159b3da..19cbe25 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -27,6 +27,7 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Parcelable; +import android.util.Log; import android.util.SparseArray; import android.view.ActionProvider; import android.view.ContextMenu.ContextMenuInfo; @@ -47,7 +48,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * standard menu UI. */ public class MenuBuilder implements Menu { - private static final String LOGTAG = "MenuBuilder"; + private static final String TAG = "MenuBuilder"; private static final String PRESENTER_KEY = "android:menu:presenters"; private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates"; diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index b0a002d..8b53bb8 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -563,7 +563,7 @@ public final class MenuItemImpl implements MenuItem { public MenuItem setActionView(int resId) { final Context context = mMenu.getContext(); final LayoutInflater inflater = LayoutInflater.from(context); - setActionView(inflater.inflate(resId, new LinearLayout(context))); + setActionView(inflater.inflate(resId, new LinearLayout(context), false)); return this; } diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 09262e0..468f28e 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -1323,11 +1323,18 @@ public class ActionBarView extends AbsActionBarView { if (mExpandedActionView instanceof CollapsibleActionView) { ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded(); } + return true; } @Override public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { + // Do this before detaching the actionview from the hierarchy, in case + // it needs to dismiss the soft keyboard, etc. + if (mExpandedActionView instanceof CollapsibleActionView) { + ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed(); + } + removeView(mExpandedActionView); removeView(mExpandedHomeLayout); if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0) { @@ -1349,16 +1356,12 @@ public class ActionBarView extends AbsActionBarView { if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { mCustomNavView.setVisibility(VISIBLE); } - View collapsedView = mExpandedActionView; mExpandedActionView = null; mExpandedHomeLayout.setIcon(null); mCurrentExpandedItem = null; requestLayout(); item.setActionViewExpanded(false); - if (collapsedView instanceof CollapsibleActionView) { - ((CollapsibleActionView) collapsedView).onActionViewCollapsed(); - } return true; } |
