diff options
Diffstat (limited to 'core/java/android')
21 files changed, 540 insertions, 303 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2c2a493..0776e10 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -153,6 +153,7 @@ public final class ActivityThread { final HashMap<IBinder, Service> mServices = new HashMap<IBinder, Service>(); AppBindData mBoundApplication; + Profiler mProfiler; Configuration mConfiguration; Configuration mCompatConfiguration; Configuration mResConfiguration; @@ -364,10 +365,6 @@ public final class ActivityThread { ApplicationInfo appInfo; List<ProviderInfo> providers; ComponentName instrumentationName; - String profileFile; - ParcelFileDescriptor profileFd; - boolean autoStopProfiler; - boolean profiling; Bundle instrumentationArgs; IInstrumentationWatcher instrumentationWatcher; int debugMode; @@ -375,10 +372,23 @@ public final class ActivityThread { boolean persistent; Configuration config; CompatibilityInfo compatInfo; - boolean handlingProfiling; + + /** Initial values for {@link Profiler}. */ + String initProfileFile; + ParcelFileDescriptor initProfileFd; + boolean initAutoStopProfiler; + public String toString() { return "AppBindData{appInfo=" + appInfo + "}"; } + } + + static final class Profiler { + String profileFile; + ParcelFileDescriptor profileFd; + boolean autoStopProfiler; + boolean profiling; + boolean handlingProfiling; public void setProfiler(String file, ParcelFileDescriptor fd) { if (profiling) { if (fd != null) { @@ -661,8 +671,6 @@ public final class ActivityThread { data.appInfo = appInfo; data.providers = providers; data.instrumentationName = instrumentationName; - data.setProfiler(profileFile, profileFd); - data.autoStopProfiler = false; data.instrumentationArgs = instrumentationArgs; data.instrumentationWatcher = instrumentationWatcher; data.debugMode = debugMode; @@ -670,6 +678,9 @@ public final class ActivityThread { data.persistent = persistent; data.config = config; data.compatInfo = compatInfo; + data.initProfileFile = profileFile; + data.initProfileFd = profileFd; + data.initAutoStopProfiler = false; queueOrSendMessage(H.BIND_APPLICATION, data); } @@ -1293,8 +1304,8 @@ public final class ActivityThread { public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; boolean stopProfiling = false; - if (mBoundApplication != null && mBoundApplication.profileFd != null - && mBoundApplication.autoStopProfiler) { + if (mBoundApplication != null && mProfiler.profileFd != null + && mProfiler.autoStopProfiler) { stopProfiling = true; } if (a != null) { @@ -1320,7 +1331,7 @@ public final class ActivityThread { } while (a != null); } if (stopProfiling) { - mBoundApplication.stopProfiling(); + mProfiler.stopProfiling(); } ensureJitEnabled(); return false; @@ -1635,12 +1646,12 @@ public final class ActivityThread { } public boolean isProfiling() { - return mBoundApplication != null && mBoundApplication.profileFile != null - && mBoundApplication.profileFd == null; + return mProfiler != null && mProfiler.profileFile != null + && mProfiler.profileFd == null; } public String getProfileFilePath() { - return mBoundApplication.profileFile; + return mProfiler.profileFile; } public Looper getLooper() { @@ -1679,6 +1690,9 @@ public final class ActivityThread { ContextImpl context = getSystemContext(); context.init(new LoadedApk(this, "android", context, info, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this); + + // give ourselves a default profiler + mProfiler = new Profiler(); } } @@ -1947,9 +1961,9 @@ public final class ActivityThread { unscheduleGcIdler(); if (r.profileFd != null) { - mBoundApplication.setProfiler(r.profileFile, r.profileFd); - mBoundApplication.startProfiling(); - mBoundApplication.autoStopProfiler = r.autoStopProfiler; + mProfiler.setProfiler(r.profileFile, r.profileFd); + mProfiler.startProfiling(); + mProfiler.autoStopProfiler = r.autoStopProfiler; } if (localLOGV) Slog.v( @@ -3570,10 +3584,10 @@ public final class ActivityThread { case 1: ViewDebug.startLooperProfiling(pcd.path, pcd.fd.getFileDescriptor()); break; - default: - mBoundApplication.setProfiler(pcd.path, pcd.fd); - mBoundApplication.autoStopProfiler = false; - mBoundApplication.startProfiling(); + default: + mProfiler.setProfiler(pcd.path, pcd.fd); + mProfiler.autoStopProfiler = false; + mProfiler.startProfiling(); break; } } catch (RuntimeException e) { @@ -3592,7 +3606,7 @@ public final class ActivityThread { ViewDebug.stopLooperProfiling(); break; default: - mBoundApplication.stopProfiling(); + mProfiler.stopProfiling(); break; } } @@ -3685,6 +3699,11 @@ public final class ActivityThread { mConfiguration = new Configuration(data.config); mCompatConfiguration = new Configuration(data.config); + mProfiler = new Profiler(); + mProfiler.profileFile = data.initProfileFile; + mProfiler.profileFd = data.initProfileFd; + mProfiler.autoStopProfiler = data.initAutoStopProfiler; + // send up app name; do this *before* waiting for debugger Process.setArgV0(data.processName); android.ddm.DdmHandleAppName.setAppName(data.processName); @@ -3699,8 +3718,8 @@ public final class ActivityThread { } } - if (data.profileFd != null) { - data.startProfiling(); + if (mProfiler.profileFd != null) { + mProfiler.startProfiling(); } // If the app is Honeycomb MR1 or earlier, switch its AsyncTask @@ -3841,10 +3860,10 @@ public final class ActivityThread { mInstrumentation.init(this, instrContext, appContext, new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher); - if (data.profileFile != null && !ii.handleProfiling - && data.profileFd == null) { - data.handlingProfiling = true; - File file = new File(data.profileFile); + if (mProfiler.profileFile != null && !ii.handleProfiling + && mProfiler.profileFd == null) { + mProfiler.handlingProfiling = true; + File file = new File(mProfiler.profileFile); file.getParentFile().mkdirs(); Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); } @@ -3896,8 +3915,8 @@ public final class ActivityThread { /*package*/ final void finishInstrumentation(int resultCode, Bundle results) { IActivityManager am = ActivityManagerNative.getDefault(); - if (mBoundApplication.profileFile != null && mBoundApplication.handlingProfiling - && mBoundApplication.profileFd == null) { + if (mProfiler.profileFile != null && mProfiler.handlingProfiling + && mProfiler.profileFd == null) { Debug.stopMethodTracing(); } //Slog.i(TAG, "am: " + ActivityManagerNative.getDefault() diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 5c4cc87..3290b9d 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -338,7 +338,7 @@ public class SearchManager /** * Column name for suggestions cursor. <i>Optional.</i> This column may be - * used to specify the time in (@link System#currentTimeMillis + * used to specify the time in {@link System#currentTimeMillis * System.currentTImeMillis()} (wall time in UTC) when an item was last * accessed within the results-providing application. If set, this may be * used to show more-recently-used items first. diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java index 9b0a2d7..fa77bc5 100644 --- a/core/java/android/net/DhcpInfoInternal.java +++ b/core/java/android/net/DhcpInfoInternal.java @@ -24,6 +24,7 @@ import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; /** * A simple object for retrieving the results of a DHCP request. @@ -41,14 +42,18 @@ public class DhcpInfoInternal { public String serverAddress; public int leaseDuration; - private Collection<RouteInfo> routes; + private Collection<RouteInfo> mRoutes; public DhcpInfoInternal() { - routes = new ArrayList<RouteInfo>(); + mRoutes = new ArrayList<RouteInfo>(); } public void addRoute(RouteInfo routeInfo) { - routes.add(routeInfo); + mRoutes.add(routeInfo); + } + + public Collection<RouteInfo> getRoutes() { + return Collections.unmodifiableCollection(mRoutes); } private int convertToInt(String addr) { @@ -66,7 +71,7 @@ public class DhcpInfoInternal { public DhcpInfo makeDhcpInfo() { DhcpInfo info = new DhcpInfo(); info.ipAddress = convertToInt(ipAddress); - for (RouteInfo route : routes) { + for (RouteInfo route : mRoutes) { if (route.isDefaultRoute()) { info.gateway = convertToInt(route.getGateway().getHostAddress()); break; @@ -94,14 +99,14 @@ public class DhcpInfoInternal { public LinkProperties makeLinkProperties() { LinkProperties p = new LinkProperties(); p.addLinkAddress(makeLinkAddress()); - for (RouteInfo route : routes) { + for (RouteInfo route : mRoutes) { p.addRoute(route); } + //if empty, connectivity configures default DNS if (TextUtils.isEmpty(dns1) == false) { p.addDns(NetworkUtils.numericToInetAddress(dns1)); } else { - p.addDns(NetworkUtils.numericToInetAddress(serverAddress)); - Log.d(TAG, "empty dns1, use dhcp server as dns1!"); + Log.d(TAG, "makeLinkProperties with empty dns1!"); } if (TextUtils.isEmpty(dns2) == false) { p.addDns(NetworkUtils.numericToInetAddress(dns2)); @@ -111,11 +116,33 @@ public class DhcpInfoInternal { return p; } + /* Updates the DHCP fields that need to be retained from + * original DHCP request if the DHCP renewal shows them as + * being empty + */ + public void updateFromDhcpRequest(DhcpInfoInternal orig) { + if (orig == null) return; + + if (TextUtils.isEmpty(dns1)) { + dns1 = orig.dns1; + } + + if (TextUtils.isEmpty(dns2)) { + dns2 = orig.dns2; + } + + if (mRoutes.size() == 0) { + for (RouteInfo route : orig.getRoutes()) { + addRoute(route); + } + } + } + public String toString() { String routeString = ""; - for (RouteInfo route : routes) routeString += route.toString() + " | "; + for (RouteInfo route : mRoutes) routeString += route.toString() + " | "; return "addr: " + ipAddress + "/" + prefixLength + - " routes: " + routeString + + " mRoutes: " + routeString + " dns: " + dns1 + "," + dns2 + " dhcpServer: " + serverAddress + " leaseDuration: " + leaseDuration; diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java index 445b2f7..79c9395 100644 --- a/core/java/android/net/DhcpStateMachine.java +++ b/core/java/android/net/DhcpStateMachine.java @@ -63,6 +63,9 @@ public class DhcpStateMachine extends StateMachine { private PowerManager.WakeLock mDhcpRenewWakeLock; private static final String WAKELOCK_TAG = "DHCP"; + //Remember DHCP configuration from first request + private DhcpInfoInternal mDhcpInfo; + private static final int DHCP_RENEW = 0; private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW"; @@ -335,9 +338,11 @@ public class DhcpStateMachine extends StateMachine { if (dhcpAction == DhcpAction.START) { Log.d(TAG, "DHCP request on " + mInterfaceName); success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal); + mDhcpInfo = dhcpInfoInternal; } else if (dhcpAction == DhcpAction.RENEW) { Log.d(TAG, "DHCP renewal on " + mInterfaceName); success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal); + dhcpInfoInternal.updateFromDhcpRequest(mDhcpInfo); } if (success) { diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 5da3114..5f111eb 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -283,6 +283,17 @@ public final class MediaStore { */ public static final String IS_DRM = "is_drm"; + /** + * The width of the image/video in pixels. + * @hide + */ + public static final String WIDTH = "width"; + + /** + * The height of the image/video in pixels. + * @hide + */ + public static final String HEIGHT = "height"; } /** diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0dc781f..335c66b 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -23,6 +23,7 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Point; +import android.os.IRemoteCallback; import android.view.IApplicationToken; import android.view.IOnKeyguardExitResult; import android.view.IRotationWatcher; @@ -220,7 +221,7 @@ interface IWindowManager void setPointerSpeed(int speed); /** - * Block until all windows the window manager knows about have been drawn. + * Block until the given window has been drawn to the screen. */ - void waitForAllDrawn(); + void waitForWindowDrawn(IBinder token, in IRemoteCallback callback); } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index c7b59b8..b678c7d 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -290,6 +290,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000; /** + * When set, this ViewGroup will not dispatch onAttachedToWindow calls + * to children when adding new views. This is used to prevent multiple + * onAttached calls when a ViewGroup adds children in its own onAttached method. + */ + private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000; + + /** * Indicates which types of drawing caches are to be kept in memory. * This field should be made private, so it is hidden from the SDK. * {@hide} @@ -2154,8 +2161,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ @Override void dispatchAttachedToWindow(AttachInfo info, int visibility) { + mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; super.dispatchAttachedToWindow(info, visibility); + mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; + visibility |= mViewFlags & VISIBILITY_MASK; + final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < count; i++) { @@ -3321,7 +3332,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } AttachInfo ai = mAttachInfo; - if (ai != null) { + if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) { boolean lastKeepOn = ai.mKeepScreenOn; ai.mKeepScreenOn = false; child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK)); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4611984..9cb4e5e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1054,7 +1054,6 @@ public final class ViewRootImpl extends Handler implements ViewParent, || attachInfo.mSystemUiVisibility != oldVis || attachInfo.mHasSystemUiListeners) { params = lp; - windowAttributesChanges |= WindowManager.LayoutParams.BUFFER_CHANGED; } } diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index fb87e23..122865e 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -34,10 +34,12 @@ import android.media.ToneGenerator; import android.net.Uri; import android.os.Handler; import android.os.Message; +import android.os.RemoteException; import android.os.Vibrator; import android.provider.Settings; import android.provider.Settings.System; import android.util.Log; +import android.view.WindowManager.LayoutParams; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; @@ -175,20 +177,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie View view = mView = inflater.inflate(R.layout.volume_adjust, null); mView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { - // Dismiss the dialog if the user touches outside the visible area. This is not - // handled by the usual dialog dismissing code because there is a region above - // the panel (marginTop) that is still within the dialog. - if (event.getAction() == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - if (x < mPanel.getLeft() || x > mPanel.getRight() || y < mPanel.getTop() - || y > mPanel.getBottom()) { - forceTimeout(); - return true; - } - } resetTimeout(); - return true; + return false; } }); mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel); @@ -196,7 +186,15 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie mMoreButton = (ImageView) mView.findViewById(R.id.expand_button); mDivider = (ImageView) mView.findViewById(R.id.expand_button_divider); - mDialog = new Dialog(context, R.style.Theme_Panel_Volume); + mDialog = new Dialog(context, R.style.Theme_Panel_Volume) { + public boolean onTouchEvent(MotionEvent event) { + if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE) { + forceTimeout(); + return true; + } + return false; + } + }; mDialog.setTitle("Volume control"); // No need to localize mDialog.setContentView(mView); mDialog.setOnDismissListener(new OnDismissListener() { @@ -208,11 +206,17 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie // Change some window properties Window window = mDialog.getWindow(); window.setGravity(Gravity.TOP); - WindowManager.LayoutParams lp = window.getAttributes(); + LayoutParams lp = window.getAttributes(); lp.token = null; - lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; + // Offset from the top + lp.y = mContext.getResources().getDimensionPixelOffset( + com.android.internal.R.dimen.volume_panel_top); + lp.type = LayoutParams.TYPE_VOLUME_OVERLAY; + lp.width = LayoutParams.WRAP_CONTENT; + lp.height = LayoutParams.WRAP_CONTENT; window.setAttributes(lp); - window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL + | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()]; mVibrator = new Vibrator(); diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 980e454..c07faf6 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -772,15 +772,26 @@ public interface WindowManagerPolicy { */ public void screenTurnedOff(int why); + public interface ScreenOnListener { + void onScreenOn(); + }; + + /** + * Called when the power manager would like to turn the screen on. + * Must call back on the listener to tell it when the higher-level system + * is ready for the screen to go on (i.e. the lock screen is shown). + */ + public void screenTurningOn(ScreenOnListener screenOnListener); + /** - * Called after the screen turns on. + * Return whether the screen is about to turn on or is currently on. */ - public void screenTurnedOn(); + public boolean isScreenOnEarly(); /** - * Return whether the screen is currently on. + * Return whether the screen is fully turned on. */ - public boolean isScreenOn(); + public boolean isScreenOnFully(); /** * Tell the policy that the lid switch has changed state. diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java index 313f755..a699800 100644 --- a/core/java/android/webkit/CookieSyncManager.java +++ b/core/java/android/webkit/CookieSyncManager.java @@ -88,6 +88,10 @@ public final class CookieSyncManager extends WebSyncManager { */ public static synchronized CookieSyncManager createInstance( Context context) { + if (context == null) { + throw new IllegalArgumentException("Invalid context argument"); + } + JniUtil.setContext(context); Context appContext = context.getApplicationContext(); if (sRef == null) { diff --git a/core/java/android/webkit/JniUtil.java b/core/java/android/webkit/JniUtil.java index ef1641d..7759ff3 100644 --- a/core/java/android/webkit/JniUtil.java +++ b/core/java/android/webkit/JniUtil.java @@ -39,25 +39,21 @@ class JniUtil { private static Boolean sUseChromiumHttpStack; private static Context sContext; - private static boolean initialized = false; - private static void checkInitialized() { - if (!initialized) { + if (sContext == null) { throw new IllegalStateException("Call CookieSyncManager::createInstance() or create a webview before using this class"); } } protected static synchronized void setContext(Context context) { - if (initialized) + if (sContext != null) { return; + } sContext = context.getApplicationContext(); - initialized = true; } protected static synchronized Context getContext() { - if (!initialized) - return null; return sContext; } @@ -68,8 +64,9 @@ class JniUtil { private static synchronized String getDatabaseDirectory() { checkInitialized(); - if (sDatabaseDirectory == null) + if (sDatabaseDirectory == null) { sDatabaseDirectory = sContext.getDatabasePath("dummy").getParent(); + } return sDatabaseDirectory; } @@ -81,8 +78,9 @@ class JniUtil { private static synchronized String getCacheDirectory() { checkInitialized(); - if (sCacheDirectory == null) + if (sCacheDirectory == null) { sCacheDirectory = sContext.getCacheDir().getAbsolutePath(); + } return sCacheDirectory; } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 600c899..122a717 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -644,7 +644,7 @@ public class WebView extends AbsoluteLayout private Drawable mSelectHandleLeft; private Drawable mSelectHandleRight; - static final boolean USE_WEBKIT_RINGS = true; + static final boolean USE_WEBKIT_RINGS = false; // the color used to highlight the touch rectangles private static final int HIGHLIGHT_COLOR = 0x6633b5e5; // the round corner for the highlight path @@ -730,6 +730,7 @@ public class WebView extends AbsoluteLayout static final int SELECT_AT = 135; static final int SCREEN_ON = 136; static final int ENTER_FULLSCREEN_VIDEO = 137; + static final int UPDATE_SELECTION = 138; private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID; private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS; @@ -1054,6 +1055,10 @@ public class WebView extends AbsoluteLayout super(context, attrs, defStyle); checkThread(); + if (context == null) { + throw new IllegalArgumentException("Invalid context argument"); + } + // Used by the chrome stack to find application paths JniUtil.setContext(context); @@ -4062,8 +4067,11 @@ public class WebView extends AbsoluteLayout // state. // If mNativeClass is 0, we should not reach here, so we do not // need to check it again. + boolean pressed = (mTouchMode == TOUCH_SHORTPRESS_START_MODE + || mTouchMode == TOUCH_INIT_MODE + || mTouchMode == TOUCH_SHORTPRESS_MODE); nativeRecordButtons(hasFocus() && hasWindowFocus(), - (mTouchMode == TOUCH_SHORTPRESS_START_MODE && !USE_WEBKIT_RINGS) + (pressed && !USE_WEBKIT_RINGS) || mTrackballDown || mGotCenterDown, false); drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing && drawRings); @@ -4280,7 +4288,6 @@ public class WebView extends AbsoluteLayout } nativeSetExtendSelection(); mDrawSelectionPointer = false; - mSelectionStarted = true; mTouchMode = TOUCH_DRAG_MODE; return true; } @@ -6532,6 +6539,8 @@ public class WebView extends AbsoluteLayout mLastTouchTime = eventTime; mVelocityTracker = VelocityTracker.obtain(); mSnapScrollMode = SNAP_NONE; + mPrivateHandler.sendEmptyMessageDelayed(UPDATE_SELECTION, + ViewConfiguration.getTapTimeout()); } private void startDrag() { @@ -7194,10 +7203,15 @@ public class WebView extends AbsoluteLayout return mZoomManager.zoomOut(); } + /** + * This selects the best clickable target at mLastTouchX and mLastTouchY + * and calls showCursorTimed on the native side + */ private void updateSelection() { if (mNativeClass == 0) { return; } + mPrivateHandler.removeMessages(UPDATE_SELECTION); // mLastTouchX and mLastTouchY are the point in the current viewport int contentX = viewToContentX(mLastTouchX + mScrollX); int contentY = viewToContentY(mLastTouchY + mScrollY); @@ -7297,6 +7311,7 @@ public class WebView extends AbsoluteLayout return; } mTouchMode = TOUCH_DONE_MODE; + updateSelection(); switchOutDrawHistory(); // mLastTouchX and mLastTouchY are the point in the current viewport int contentX = viewToContentX(mLastTouchX + mScrollX); @@ -8187,6 +8202,14 @@ public class WebView extends AbsoluteLayout SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL); break; } + case UPDATE_SELECTION: { + if (mTouchMode == TOUCH_INIT_MODE + || mTouchMode == TOUCH_SHORTPRESS_MODE + || mTouchMode == TOUCH_SHORTPRESS_START_MODE) { + updateSelection(); + } + break; + } case SWITCH_TO_SHORTPRESS: { mInitialHitTestResult = null; // set by updateSelection() if (mTouchMode == TOUCH_INIT_MODE) { diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 72db8e8..5392c2e 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -277,10 +277,11 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { * called, false otherwise is returned. */ public boolean performItemClick(View view, int position, long id) { - view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); - if (mOnItemClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); + if (view != null) { + view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); + } mOnItemClickListener.onItemClick(this, view, position, id); return true; } @@ -338,8 +339,10 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { */ public interface OnItemSelectedListener { /** - * Callback method to be invoked when an item in this view has been - * selected. + * <p>Callback method to be invoked when an item in this view has been + * selected. This callback is invoked only when the newly selected + * position is different from the previously selected position or if + * there was no selected item.</p> * * Impelmenters can call getItemAtPosition(position) if they need to access the * data associated with the selected item. diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 27610b9..07523e3 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -16,8 +16,6 @@ package android.widget; -import com.android.internal.R; - import android.content.Context; import android.content.res.TypedArray; import android.database.DataSetObserver; @@ -38,6 +36,8 @@ import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; +import com.android.internal.R; + /** * <p>An editable text view that shows completion suggestions automatically @@ -744,7 +744,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe if (mFilter != null) { mPopupCanBeUpdated = true; performFiltering(getText(), mLastKeyCode); - buildImeCompletions(); } } else { // drop down is automatically dismissed when enough characters @@ -837,10 +836,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe @Override public void onCommitCompletion(CompletionInfo completion) { if (isPopupShowing()) { - mBlockCompletion = true; - replaceText(completion.getText()); - mBlockCompletion = false; - mPopup.performItemClick(completion.getPosition()); } } @@ -938,7 +933,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe */ final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible(); - if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter()) { + final boolean enoughToFilter = enoughToFilter(); + if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter) { if (hasFocus() && hasWindowFocus() && mPopupCanBeUpdated) { showDropDown(); } @@ -1049,6 +1045,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * <p>Displays the drop down on screen.</p> */ public void showDropDown() { + buildImeCompletions(); + if (mPopup.getAnchorView() == null) { if (mDropDownAnchorId != View.NO_ID) { mPopup.setAnchorView(getRootView().findViewById(mDropDownAnchorId)); @@ -1064,7 +1062,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe mPopup.show(); mPopup.getListView().setOverScrollMode(View.OVER_SCROLL_ALWAYS); } - + /** * Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is * false, we allow outside touch to dismiss the dropdown. If this is set to true, then we @@ -1075,7 +1073,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) { mPopup.setForceIgnoreOutsideTouch(forceIgnoreOutsideTouch); } - + private void buildImeCompletions() { final ListAdapter adapter = mAdapter; if (adapter != null) { @@ -1090,8 +1088,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe realCount++; Object item = adapter.getItem(i); long id = adapter.getItemId(i); - completions[i] = new CompletionInfo(id, i, - convertSelectionToString(item)); + completions[i] = new CompletionInfo(id, i, convertSelectionToString(item)); } } diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 1b713c3..9cbe8db 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -339,10 +339,8 @@ public class CalendarView extends FrameLayout { // initialization based on locale setCurrentLocale(Locale.getDefault()); - TypedValue calendarViewStyle = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.calendarViewStyle, calendarViewStyle, true); - TypedArray attributesArray = context.obtainStyledAttributes(calendarViewStyle.resourceId, - R.styleable.CalendarView); + TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.CalendarView, + R.attr.calendarViewStyle, 0); mShowWeekNumber = attributesArray.getBoolean(R.styleable.CalendarView_showWeekNumber, DEFAULT_SHOW_WEEK_NUMBER); mFirstDayOfWeek = attributesArray.getInt(R.styleable.CalendarView_firstDayOfWeek, @@ -355,6 +353,9 @@ public class CalendarView extends FrameLayout { if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, mMaxDate)) { parseDate(DEFAULT_MAX_DATE, mMaxDate); } + if (mMaxDate.before(mMinDate)) { + throw new IllegalArgumentException("Max date cannot be before min date."); + } mShownWeekCount = attributesArray.getInt(R.styleable.CalendarView_shownWeekCount, DEFAULT_SHOWN_WEEK_COUNT); mSelectedWeekBackgroundColor = attributesArray.getColor( @@ -407,9 +408,16 @@ public class CalendarView extends FrameLayout { setUpListView(); setUpAdapter(); - // go to today now + // go to today or whichever is close to today min or max date mTempDate.setTimeInMillis(System.currentTimeMillis()); - goTo(mTempDate, false, true, true); + if (mTempDate.before(mMinDate)) { + goTo(mMinDate, false, true, true); + } else if (mMaxDate.before(mTempDate)) { + goTo(mMaxDate, false, true, true); + } else { + goTo(mTempDate, false, true, true); + } + invalidate(); } diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 390002b..ba69288 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -87,19 +87,26 @@ import static java.lang.Math.min; * layout parameters. When the * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} * property is set, default margins around children are automatically - * allocated based on the child's visual characteristics. Each of the - * margins so defined may be independently overridden by an assignment + * allocated based on the prevailing UI style guide for the platform. + * Each of the margins so defined may be independently overridden by an assignment * to the appropriate layout parameter. + * Default values will generally produce a reasonable spacing between components + * but values may change between different releases of the platform. * * <h4>Excess Space Distribution</h4> * + * GridLayout's distribution of excess space is based on <em>priority</em> + * rather than <em>weight</em>. + * <p> * A child's ability to stretch is inferred from the alignment properties of * its row and column groups (which are typically set by setting the * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters). * If alignment was defined along a given axis then the component - * is taken as flexible in along that axis. If no alignment was set, - * the component is instead assumed to be inflexible. Multiple components in - * the same row or column group are considered to act in <em>parallel</em>. Such a + * is taken as <em>flexible</em> in that direction. If no alignment was set, + * the component is instead assumed to be <em>inflexible</em>. + * <p> + * Multiple components in the same row or column group are + * considered to act in <em>parallel</em>. Such a * group is flexible only if <em>all</em> of the components * within it are flexible. Row and column groups that sit either side of a common boundary * are instead considered to act in <em>series</em>. The composite group made of these two @@ -109,6 +116,23 @@ import static java.lang.Math.min; * gravity. To prevent a column from stretching, ensure that one of the components * in the column does not define a gravity. * <p> + * When the principle of flexibility does not provide complete disambiguation, + * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em> + * and <em>bottom</em> edges. + * + * <h5>Limitations</h5> + * + * GridLayout does not provide support for the principle of <em>weight</em>, as defined in + * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible + * to configure a GridLayout to distribute excess space in non-trivial proportions between + * multiple rows or columns. + * <p> + * Some common use-cases may nevertheless be accommodated as follows. + * To place equal amounts of space around a component in a cell group; + * use {@link #CENTER} alignment (or {@link LayoutParams#setGravity(int) gravity}). + * For complete control over excess space distribution in a row or column; + * use a {@link LinearLayout} subview to hold the components in the associated cell group. + * When using either of these techniques, bear in mind that cell groups may be defined to overlap. * <p> * See {@link GridLayout.LayoutParams} for a full description of the * layout parameters used by GridLayout. @@ -180,9 +204,11 @@ public class GridLayout extends ViewGroup { // Misc constants - private static final String TAG = GridLayout.class.getName(); - private static boolean DEBUG = false; - private static final int PRF = 1; + static final String TAG = GridLayout.class.getName(); + static final boolean DEBUG = false; + static final int PRF = 1; + static final int MAX_SIZE = 100000; + static final int DEFAULT_CONTAINER_MARGIN = 0; // Defaults @@ -191,8 +217,6 @@ public class GridLayout extends ViewGroup { private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false; private static final boolean DEFAULT_ORDER_PRESERVED = true; private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS; - private static final int DEFAULT_CONTAINER_MARGIN = 0; - private static final int MAX_SIZE = 100000; // TypedArray indices @@ -206,13 +230,13 @@ public class GridLayout extends ViewGroup { // Instance variables - private final Axis mHorizontalAxis = new Axis(true); - private final Axis mVerticalAxis = new Axis(false); - private boolean mLayoutParamsValid = false; - private int mOrientation = DEFAULT_ORIENTATION; - private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS; - private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE; - private int mDefaultGap; + final Axis horizontalAxis = new Axis(true); + final Axis verticalAxis = new Axis(false); + boolean layoutParamsValid = false; + int orientation = DEFAULT_ORIENTATION; + boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS; + int alignmentMode = DEFAULT_ALIGNMENT_MODE; + int defaultGap; // Constructors @@ -224,7 +248,7 @@ public class GridLayout extends ViewGroup { if (DEBUG) { setWillNotDraw(false); } - mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap); + defaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout); try { setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT)); @@ -266,13 +290,12 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_orientation */ public int getOrientation() { - return mOrientation; + return orientation; } /** - * The orientation property does not affect layout. Orientation is used - * only to generate default row/column indices when they are not specified - * by a component's layout parameters. + * Orientation is used only to generate default row/column indices when + * they are not specified by a component's layout parameters. * <p> * The default value of this property is {@link #HORIZONTAL}. * @@ -283,8 +306,9 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_orientation */ public void setOrientation(int orientation) { - if (mOrientation != orientation) { - mOrientation = orientation; + if (this.orientation != orientation) { + this.orientation = orientation; + invalidateStructure(); requestLayout(); } } @@ -302,13 +326,12 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_rowCount */ public int getRowCount() { - return mVerticalAxis.getCount(); + return verticalAxis.getCount(); } /** - * The rowCount property does not affect layout. RowCount is used - * only to generate default row/column indices when they are not specified - * by a component's layout parameters. + * RowCount is used only to generate default row/column indices when + * they are not specified by a component's layout parameters. * * @param rowCount the number of rows * @@ -318,7 +341,9 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_rowCount */ public void setRowCount(int rowCount) { - mVerticalAxis.setCount(rowCount); + verticalAxis.setCount(rowCount); + invalidateStructure(); + requestLayout(); } /** @@ -334,13 +359,12 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_columnCount */ public int getColumnCount() { - return mHorizontalAxis.getCount(); + return horizontalAxis.getCount(); } /** - * The columnCount property does not affect layout. ColumnCount is used - * only to generate default column/column indices when they are not specified - * by a component's layout parameters. + * ColumnCount is used only to generate default column/column indices when + * they are not specified by a component's layout parameters. * * @param columnCount the number of columns. * @@ -350,7 +374,9 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_columnCount */ public void setColumnCount(int columnCount) { - mHorizontalAxis.setCount(columnCount); + horizontalAxis.setCount(columnCount); + invalidateStructure(); + requestLayout(); } /** @@ -364,7 +390,7 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_useDefaultMargins */ public boolean getUseDefaultMargins() { - return mUseDefaultMargins; + return useDefaultMargins; } /** @@ -394,7 +420,7 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_useDefaultMargins */ public void setUseDefaultMargins(boolean useDefaultMargins) { - mUseDefaultMargins = useDefaultMargins; + this.useDefaultMargins = useDefaultMargins; requestLayout(); } @@ -411,7 +437,7 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_alignmentMode */ public int getAlignmentMode() { - return mAlignmentMode; + return alignmentMode; } /** @@ -430,7 +456,7 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_alignmentMode */ public void setAlignmentMode(int alignmentMode) { - mAlignmentMode = alignmentMode; + this.alignmentMode = alignmentMode; requestLayout(); } @@ -445,7 +471,7 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_rowOrderPreserved */ public boolean isRowOrderPreserved() { - return mVerticalAxis.isOrderPreserved(); + return verticalAxis.isOrderPreserved(); } /** @@ -465,7 +491,7 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_rowOrderPreserved */ public void setRowOrderPreserved(boolean rowOrderPreserved) { - mVerticalAxis.setOrderPreserved(rowOrderPreserved); + verticalAxis.setOrderPreserved(rowOrderPreserved); invalidateStructure(); requestLayout(); } @@ -481,7 +507,7 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_columnOrderPreserved */ public boolean isColumnOrderPreserved() { - return mHorizontalAxis.isOrderPreserved(); + return horizontalAxis.isOrderPreserved(); } /** @@ -501,14 +527,14 @@ public class GridLayout extends ViewGroup { * @attr ref android.R.styleable#GridLayout_columnOrderPreserved */ public void setColumnOrderPreserved(boolean columnOrderPreserved) { - mHorizontalAxis.setOrderPreserved(columnOrderPreserved); + horizontalAxis.setOrderPreserved(columnOrderPreserved); invalidateStructure(); requestLayout(); } // Static utility methods - private static int max2(int[] a, int valueIfEmpty) { + static int max2(int[] a, int valueIfEmpty) { int result = valueIfEmpty; for (int i = 0, N = a.length; i < N; i++) { result = Math.max(result, a[i]); @@ -517,14 +543,14 @@ public class GridLayout extends ViewGroup { } @SuppressWarnings("unchecked") - private static <T> T[] append(T[] a, T[] b) { + static <T> T[] append(T[] a, T[] b) { T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length); System.arraycopy(a, 0, result, 0, a.length); System.arraycopy(b, 0, result, a.length, b.length); return result; } - private static Alignment getAlignment(int gravity, boolean horizontal) { + static Alignment getAlignment(int gravity, boolean horizontal) { int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK; int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT; int flags = (gravity & mask) >> shift; @@ -547,7 +573,7 @@ public class GridLayout extends ViewGroup { if (c.getClass() == Space.class) { return 0; } - return mDefaultGap / 2; + return defaultGap / 2; } private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) { @@ -555,18 +581,18 @@ public class GridLayout extends ViewGroup { } private int getDefaultMarginValue(View c, LayoutParams p, boolean horizontal, boolean leading) { - if (!mUseDefaultMargins) { + if (!useDefaultMargins) { return 0; } Spec spec = horizontal ? p.columnSpec : p.rowSpec; - Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; + Axis axis = horizontal ? horizontalAxis : verticalAxis; Interval span = spec.span; boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount()); return getDefaultMargin(c, isAtEdge, horizontal, leading); } - private int getMargin1(View view, boolean horizontal, boolean leading) { + int getMargin1(View view, boolean horizontal, boolean leading) { LayoutParams lp = getLayoutParams(view); int margin = horizontal ? (leading ? lp.leftMargin : lp.rightMargin) : @@ -575,10 +601,10 @@ public class GridLayout extends ViewGroup { } private int getMargin(View view, boolean horizontal, boolean leading) { - if (mAlignmentMode == ALIGN_MARGINS) { + if (alignmentMode == ALIGN_MARGINS) { return getMargin1(view, horizontal, leading); } else { - Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; + Axis axis = horizontal ? horizontalAxis : verticalAxis; int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins(); LayoutParams lp = getLayoutParams(view); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; @@ -591,10 +617,6 @@ public class GridLayout extends ViewGroup { return getMargin(child, horizontal, true) + getMargin(child, horizontal, false); } - private static int valueIfDefined(int value, int defaultValue) { - return (value != UNDEFINED) ? value : defaultValue; - } - private static boolean fits(int[] a, int value, int start, int end) { if (end > a.length) { return false; @@ -629,9 +651,9 @@ public class GridLayout extends ViewGroup { // install default indices for cells that don't define them private void validateLayoutParams() { - final boolean horizontal = (mOrientation == HORIZONTAL); - final int axisCount = horizontal ? mHorizontalAxis.count : mVerticalAxis.count; - final int count = valueIfDefined(axisCount, 0); + final boolean horizontal = (orientation == HORIZONTAL); + final Axis axis = horizontal ? horizontalAxis : verticalAxis; + final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0; int major = 0; int minor = 0; @@ -640,15 +662,17 @@ public class GridLayout extends ViewGroup { for (int i = 0, N = getChildCount(); i < N; i++) { LayoutParams lp = getLayoutParams1(getChildAt(i)); - final Interval majorRange = (horizontal ? lp.rowSpec : lp.columnSpec).span; - final boolean majorWasDefined = (majorRange.min != UNDEFINED); + final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec; + final Interval majorRange = majorSpec.span; + final boolean majorWasDefined = majorSpec.startDefined; final int majorSpan = majorRange.size(); if (majorWasDefined) { major = majorRange.min; } - final Interval minorRange = (horizontal ? lp.columnSpec : lp.rowSpec).span; - final boolean minorWasDefined = (minorRange.min != UNDEFINED); + final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec; + final Interval minorRange = minorSpec.span; + final boolean minorWasDefined = minorSpec.startDefined; final int minorSpan = clip(minorRange, minorWasDefined, count); if (minorWasDefined) { minor = minorRange.min; @@ -685,9 +709,9 @@ public class GridLayout extends ViewGroup { } private void invalidateStructure() { - mLayoutParamsValid = false; - mHorizontalAxis.invalidateStructure(); - mVerticalAxis.invalidateStructure(); + layoutParamsValid = false; + horizontalAxis.invalidateStructure(); + verticalAxis.invalidateStructure(); // This can end up being done twice. Better twice than not at all. invalidateValues(); } @@ -695,9 +719,9 @@ public class GridLayout extends ViewGroup { private void invalidateValues() { // Need null check because requestLayout() is called in View's initializer, // before we are set up. - if (mHorizontalAxis != null && mVerticalAxis != null) { - mHorizontalAxis.invalidateValues(); - mVerticalAxis.invalidateValues(); + if (horizontalAxis != null && verticalAxis != null) { + horizontalAxis.invalidateValues(); + verticalAxis.invalidateValues(); } } @@ -705,10 +729,10 @@ public class GridLayout extends ViewGroup { return (LayoutParams) c.getLayoutParams(); } - private LayoutParams getLayoutParams(View c) { - if (!mLayoutParamsValid) { + final LayoutParams getLayoutParams(View c) { + if (!layoutParamsValid) { validateLayoutParams(); - mLayoutParamsValid = true; + layoutParamsValid = true; } return getLayoutParams1(c); } @@ -752,7 +776,7 @@ public class GridLayout extends ViewGroup { paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.argb(50, 255, 255, 255)); - int[] xs = mHorizontalAxis.locations; + int[] xs = horizontalAxis.locations; if (xs != null) { for (int i = 0, length = xs.length; i < length; i++) { int x = xs[i]; @@ -760,7 +784,7 @@ public class GridLayout extends ViewGroup { } } - int[] ys = mVerticalAxis.locations; + int[] ys = verticalAxis.locations; if (ys != null) { for (int i = 0, length = ys.length; i < length; i++) { int y = ys[i]; @@ -822,7 +846,7 @@ public class GridLayout extends ViewGroup { // Measurement - private boolean isGone(View c) { + final boolean isGone(View c) { return c.getVisibility() == View.GONE; } @@ -847,8 +871,8 @@ public class GridLayout extends ViewGroup { protected void onMeasure(int widthSpec, int heightSpec) { measureChildrenWithMargins(widthSpec, heightSpec); - int width = getPaddingLeft() + mHorizontalAxis.getMeasure(widthSpec) + getPaddingRight(); - int height = getPaddingTop() + mVerticalAxis.getMeasure(heightSpec) + getPaddingBottom(); + int width = getPaddingLeft() + horizontalAxis.getMeasure(widthSpec) + getPaddingRight(); + int height = getPaddingTop() + verticalAxis.getMeasure(heightSpec) + getPaddingBottom(); int measuredWidth = Math.max(width, getSuggestedMinimumWidth()); int measuredHeight = Math.max(height, getSuggestedMinimumHeight()); @@ -866,7 +890,7 @@ public class GridLayout extends ViewGroup { return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight(); } - private int getMeasurementIncludingMargin(View c, boolean horizontal) { + final int getMeasurementIncludingMargin(View c, boolean horizontal) { if (isGone(c)) { return 0; } @@ -879,7 +903,7 @@ public class GridLayout extends ViewGroup { invalidateValues(); } - private Alignment getAlignment(Alignment alignment, boolean horizontal) { + final Alignment getAlignment(Alignment alignment, boolean horizontal) { return (alignment != UNDEFINED_ALIGNMENT) ? alignment : (horizontal ? LEFT : BASELINE); } @@ -908,11 +932,11 @@ public class GridLayout extends ViewGroup { int paddingRight = getPaddingRight(); int paddingBottom = getPaddingBottom(); - mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight); - mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom); + horizontalAxis.layout(targetWidth - paddingLeft - paddingRight); + verticalAxis.layout(targetHeight - paddingTop - paddingBottom); - int[] hLocations = mHorizontalAxis.getLocations(); - int[] vLocations = mVerticalAxis.getLocations(); + int[] hLocations = horizontalAxis.getLocations(); + int[] vLocations = verticalAxis.getLocations(); for (int i = 0, N = getChildCount(); i < N; i++) { View c = getChildAt(i); @@ -941,8 +965,8 @@ public class GridLayout extends ViewGroup { int dx, dy; - Bounds colBounds = mHorizontalAxis.getGroupBounds().getValue(i); - Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i); + Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i); + Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i); // Gravity offsets: the location of the alignment group relative to its cell group. //noinspection NullableProblems @@ -990,7 +1014,7 @@ public class GridLayout extends ViewGroup { distinguished by the "horizontal" flag which is true for the horizontal axis and false for the vertical one. */ - private class Axis { + final class Axis { private static final int MIN_VALUE = -1000000; private static final int NEW = 0; @@ -999,9 +1023,8 @@ public class GridLayout extends ViewGroup { public final boolean horizontal; - public int count = UNDEFINED; - public boolean countValid = false; - public boolean countWasExplicitySet = false; + public int definedCount = UNDEFINED; + private int inferredCount = UNDEFINED; PackedMap<Spec, Bounds> groupBounds; public boolean groupBoundsValid = false; @@ -1024,7 +1047,7 @@ public class GridLayout extends ViewGroup { public int[] locations; public boolean locationsValid = false; - private boolean mOrderPreserved = DEFAULT_ORDER_PRESERVED; + boolean orderPreserved = DEFAULT_ORDER_PRESERVED; private MutableInt parentMin = new MutableInt(0); private MutableInt parentMax = new MutableInt(-MAX_SIZE); @@ -1046,25 +1069,27 @@ public class GridLayout extends ViewGroup { return count == -1 ? UNDEFINED : count; } - public int getCount() { - if (!countValid) { - count = max(0, maxIndex()); // if there are no cells, the count is zero - countValid = true; + private int getInferredCount() { + if (inferredCount == UNDEFINED) { + inferredCount = max(0, maxIndex()); // if there are no cells, actual count is zero } - return count; + return inferredCount; + } + + public int getCount() { + return max(definedCount, getInferredCount()); } public void setCount(int count) { - this.count = count; - this.countWasExplicitySet = count != UNDEFINED; + this.definedCount = count; } public boolean isOrderPreserved() { - return mOrderPreserved; + return orderPreserved; } public void setOrderPreserved(boolean orderPreserved) { - mOrderPreserved = orderPreserved; + this.orderPreserved = orderPreserved; invalidateStructure(); } @@ -1093,7 +1118,7 @@ public class GridLayout extends ViewGroup { } } - private PackedMap<Spec, Bounds> getGroupBounds() { + public PackedMap<Spec, Bounds> getGroupBounds() { if (groupBounds == null) { groupBounds = createGroupBounds(); } @@ -1183,7 +1208,7 @@ public class GridLayout extends ViewGroup { // Group arcs by their first vertex, returning an array of arrays. // This is linear in the number of arcs. - private Arc[][] groupArcsByFirstVertex(Arc[] arcs) { + Arc[][] groupArcsByFirstVertex(Arc[] arcs) { int N = getCount() + 1; // the number of vertices Arc[][] result = new Arc[N][]; int[] sizes = new int[N]; @@ -1262,7 +1287,7 @@ public class GridLayout extends ViewGroup { addComponentSizes(maxs, getBackwardLinks()); // Add ordering constraints to prevent row/col sizes from going negative - if (mOrderPreserved) { + if (orderPreserved) { // Add a constraint for every row/col for (int i = 0; i < getCount(); i++) { include(mins, new Interval(i, i + 1), new MutableInt(0)); @@ -1315,6 +1340,48 @@ public class GridLayout extends ViewGroup { return false; } + private void init(int[] locations) { + Arrays.fill(locations, MIN_VALUE); + locations[0] = 0; + } + + private String arcsToString(List<Arc> arcs) { + String var = horizontal ? "c" : "r"; + StringBuilder result = new StringBuilder(); + boolean first = false; + for(Arc arc : arcs) { + if (!first) { + first = true; + } else { + result =result.append(", "); + } + int src = arc.span.min; + int dst = arc.span.max; + int value = arc.value.value; + result.append((src < dst) ? + var + dst + " - " + var + src + " > " + value : + var + src + " - " + var + dst + " < " + -value); + + } + return result.toString(); + } + + private void logError(String axisName, Arc[] arcs, boolean[] culprits0) { + List<Arc> culprits = new ArrayList<Arc>(); + List<Arc> removed = new ArrayList<Arc>(); + for (int c = 0; c < arcs.length; c++) { + Arc arc = arcs[c]; + if (culprits0[c]) { + culprits.add(arc); + } + if (!arc.valid) { + removed.add(arc); + } + } + Log.d(TAG, axisName + " constraints: " + arcsToString(culprits) + " are inconsistent; " + + "permanently removing: " + arcsToString(removed) + ". "); + } + /* Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N) @@ -1350,51 +1417,54 @@ public class GridLayout extends ViewGroup { completes in O(N) steps with very low constants. */ private void solve(Arc[] arcs, int[] locations) { - String axis = horizontal ? "horizontal" : "vertical"; + String axisName = horizontal ? "horizontal" : "vertical"; int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1. + boolean[] originalCulprits = null; - // We take one extra pass over traditional Bellman-Ford (and omit their final step) - for (int i = 0; i < N; i++) { - boolean changed = false; - for (int j = 0, length = arcs.length; j < length; j++) { - changed |= relax(locations, arcs[j]); - } - if (!changed) { - if (DEBUG) { - Log.v(TAG, axis + " iteration completed in " + (1 + i) + " steps of " + N); + for (int p = 0; p < arcs.length; p++) { + init(locations); + + // We take one extra pass over traditional Bellman-Ford (and omit their final step) + for (int i = 0; i < N; i++) { + boolean changed = false; + for (int j = 0, length = arcs.length; j < length; j++) { + changed |= relax(locations, arcs[j]); + } + if (!changed) { + if (originalCulprits != null) { + logError(axisName, arcs, originalCulprits); + } + if (DEBUG) { + Log.v(TAG, axisName + " iteration completed in " + + (1 + i) + " steps of " + N); + } + return; } - return; } - } - Log.d(TAG, "The " + axis + " constraints contained a contradiction. Resolving... "); - Log.d(TAG, Arrays.toString(arcs)); + boolean[] culprits = new boolean[arcs.length]; + for (int i = 0; i < N; i++) { + for (int j = 0, length = arcs.length; j < length; j++) { + culprits[j] |= relax(locations, arcs[j]); + } + } - boolean[] culprits = new boolean[arcs.length]; - for (int i = 0; i < N; i++) { - for (int j = 0, length = arcs.length; j < length; j++) { - culprits[j] |= relax(locations, arcs[j]); + if (p == 0) { + originalCulprits = culprits; } - } - for (int i = 0; i < culprits.length; i++) { - if (culprits[i]) { - Arc arc = arcs[i]; - // Only remove max values, min values alone cannot be inconsistent - if (arc.span.min < arc.span.max) { - continue; + + for (int i = 0; i < arcs.length; i++) { + if (culprits[i]) { + Arc arc = arcs[i]; + // Only remove max values, min values alone cannot be inconsistent + if (arc.span.min < arc.span.max) { + continue; + } + arc.valid = false; + break; } - Log.d(TAG, "Removing: " + arc); - arc.valid = false; - break; } } - solve1(arcs, locations); - } - - private void solve1(Arc[] arcs, int[] a) { - Arrays.fill(a, MIN_VALUE); - a[0] = 0; - solve(arcs, a); } private void computeMargins(boolean leading) { @@ -1410,7 +1480,9 @@ public class GridLayout extends ViewGroup { } } - private int[] getLeadingMargins() { + // External entry points + + public int[] getLeadingMargins() { if (leadingMargins == null) { leadingMargins = new int[getCount() + 1]; } @@ -1421,7 +1493,7 @@ public class GridLayout extends ViewGroup { return leadingMargins; } - private int[] getTrailingMargins() { + public int[] getTrailingMargins() { if (trailingMargins == null) { trailingMargins = new int[getCount() + 1]; } @@ -1433,10 +1505,10 @@ public class GridLayout extends ViewGroup { } private void computeLocations(int[] a) { - solve1(getArcs(), a); + solve(getArcs(), a); } - private int[] getLocations() { + public int[] getLocations() { if (locations == null) { int N = getCount() + 1; locations = new int[N]; @@ -1448,8 +1520,6 @@ public class GridLayout extends ViewGroup { return locations; } - // External entry points - private int size(int[] locations) { return max2(locations, 0) - locations[0]; } @@ -1465,7 +1535,7 @@ public class GridLayout extends ViewGroup { return size(getLocations()); } - private int getMeasure(int measureSpec) { + public int getMeasure(int measureSpec) { int mode = MeasureSpec.getMode(measureSpec); int size = MeasureSpec.getSize(measureSpec); switch (mode) { @@ -1485,13 +1555,13 @@ public class GridLayout extends ViewGroup { } } - private void layout(int size) { + public void layout(int size) { setParentConstraints(size, size); getLocations(); } - private void invalidateStructure() { - countValid = false; + public void invalidateStructure() { + inferredCount = UNDEFINED; groupBounds = null; forwardLinks = null; @@ -1506,7 +1576,7 @@ public class GridLayout extends ViewGroup { invalidateValues(); } - private void invalidateValues() { + public void invalidateValues() { groupBoundsValid = false; forwardLinksValid = false; backwardLinksValid = false; @@ -1536,9 +1606,22 @@ public class GridLayout extends ViewGroup { * both aspects of alignment within the cell group. It is also possible to specify a child's * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)} * method. - * <p> - * See {@link GridLayout} for a description of the conventions used by GridLayout - * in reference to grid indices. + * + * <h4>WRAP_CONTENT and MATCH_PARENT</h4> + * + * Because the default values of the {@link #width} and {@link #height} + * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly + * declared in the layout parameters of GridLayout's children. In addition, + * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from + * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is + * instead controlled by the principle of <em>flexibility</em>, + * as discussed in {@link GridLayout}. + * + * <h4>Summary</h4> + * + * You should not need to use either of the special size values: + * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of + * a GridLayout. * * <h4>Default values</h4> * @@ -1561,12 +1644,17 @@ public class GridLayout extends ViewGroup { * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is * {@code false}; otherwise {@link #UNDEFINED}, to * indicate that a default value should be computed on demand. </li> - * <li>{@link #rowSpec}{@code .span} = {@code [0, 1]} </li> - * <li>{@link #rowSpec}{@code .alignment} = {@link #BASELINE} </li> - * <li>{@link #columnSpec}{@code .span} = {@code [0, 1]} </li> - * <li>{@link #columnSpec}{@code .alignment} = {@link #LEFT} </li> + * <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li> + * <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li> + * <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li> + * <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li> + * <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li> + * <li>{@link #columnSpec}<code>.alignment</code> = {@link #LEFT} </li> * </ul> * + * See {@link GridLayout} for a more complete description of the conventions + * used by GridLayout in the interpretation of the properties of this class. + * * @attr ref android.R.styleable#GridLayout_Layout_layout_row * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan * @attr ref android.R.styleable#GridLayout_Layout_layout_column @@ -1606,15 +1694,16 @@ public class GridLayout extends ViewGroup { // Instance variables /** - * The spec that specifies the vertical characteristics of the cell group + * The spec that defines the vertical characteristics of the cell group * described by these layout parameters. */ - public Spec rowSpec; + public Spec rowSpec = Spec.UNDEFINED; + /** - * The spec that specifies the horizontal characteristics of the cell group + * The spec that defines the horizontal characteristics of the cell group * described by these layout parameters. */ - public Spec columnSpec; + public Spec columnSpec = Spec.UNDEFINED; // Constructors @@ -1646,7 +1735,7 @@ public class GridLayout extends ViewGroup { * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}. */ public LayoutParams() { - this(spec(UNDEFINED), spec(UNDEFINED)); + this(Spec.UNDEFINED, Spec.UNDEFINED); } // Copying constructors @@ -1670,8 +1759,8 @@ public class GridLayout extends ViewGroup { */ public LayoutParams(LayoutParams that) { super(that); - this.rowSpec = new Spec(that.rowSpec); - this.columnSpec = new Spec(that.columnSpec); + this.rowSpec = that.rowSpec; + this.columnSpec = that.columnSpec; } // AttributeSet constructors @@ -1750,11 +1839,11 @@ public class GridLayout extends ViewGroup { this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT); } - private void setRowSpecSpan(Interval span) { + final void setRowSpecSpan(Interval span) { rowSpec = rowSpec.copyWriteSpan(span); } - private void setColumnSpecSpan(Interval span) { + final void setColumnSpecSpan(Interval span) { columnSpec = columnSpec.copyWriteSpan(span); } } @@ -1763,7 +1852,7 @@ public class GridLayout extends ViewGroup { In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs. Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles. */ - private static class Arc { + final static class Arc { public final Interval span; public final MutableInt value; public boolean valid = true; @@ -1781,18 +1870,18 @@ public class GridLayout extends ViewGroup { // A mutable Integer - used to avoid heap allocation during the layout operation - private static class MutableInt { + final static class MutableInt { public int value; - private MutableInt() { + public MutableInt() { reset(); } - private MutableInt(int value) { + public MutableInt(int value) { this.value = value; } - private void reset() { + public void reset() { value = Integer.MIN_VALUE; } @@ -1802,7 +1891,7 @@ public class GridLayout extends ViewGroup { } } - private static class Assoc<K, V> extends ArrayList<Pair<K, V>> { + final static class Assoc<K, V> extends ArrayList<Pair<K, V>> { private final Class<K> keyType; private final Class<V> valueType; @@ -1811,7 +1900,7 @@ public class GridLayout extends ViewGroup { this.valueType = valueType; } - private static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) { + public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) { return new Assoc<K, V>(keyType, valueType); } @@ -1847,7 +1936,7 @@ public class GridLayout extends ViewGroup { rather than using (and storing) an implementation of Map<Key, ?>. */ @SuppressWarnings(value = "unchecked") - private static class PackedMap<K, V> { + final static class PackedMap<K, V> { public final int[] index; public final K[] keys; public final V[] values; @@ -1859,7 +1948,7 @@ public class GridLayout extends ViewGroup { this.values = compact(values, index); } - private V getValue(int i) { + public V getValue(int i) { return values[index[i]]; } @@ -1907,7 +1996,7 @@ public class GridLayout extends ViewGroup { group to Bounds and to loop through all Views in the group taking the maximum of the values for each View. */ - private static class Bounds { + static class Bounds { public int before; public int after; public int flexibility; // we're flexible iff all included specs are flexible @@ -1969,7 +2058,7 @@ public class GridLayout extends ViewGroup { * Intervals are often written as {@code [min, max]} and represent the set of values * {@code x} such that {@code min <= x < max}. */ - static class Interval { + final static class Interval { /** * The minimum value. */ @@ -1995,11 +2084,11 @@ public class GridLayout extends ViewGroup { this.max = max; } - private int size() { + int size() { return max - min; } - private Interval inverse() { + Interval inverse() { return new Interval(max, min); } @@ -2062,32 +2151,31 @@ public class GridLayout extends ViewGroup { * For column groups, this specifies the horizontal alignment. */ public static class Spec { + static final Spec UNDEFINED = spec(GridLayout.UNDEFINED); + + final boolean startDefined; final Interval span; final Alignment alignment; - private Spec(Interval span, Alignment alignment) { + private Spec(boolean startDefined, Interval span, Alignment alignment) { + this.startDefined = startDefined; this.span = span; this.alignment = alignment; } - /* Copying constructor */ - private Spec(Spec that) { - this(that.span, that.alignment); - } - - private Spec(int start, int size, Alignment alignment) { - this(new Interval(start, start + size), alignment); + private Spec(boolean startDefined, int start, int size, Alignment alignment) { + this(startDefined, new Interval(start, start + size), alignment); } - private Spec copyWriteSpan(Interval span) { - return new Spec(span, alignment); + final Spec copyWriteSpan(Interval span) { + return new Spec(startDefined, span, alignment); } - private Spec copyWriteAlignment(Alignment alignment) { - return new Spec(span, alignment); + final Spec copyWriteAlignment(Alignment alignment) { + return new Spec(startDefined, span, alignment); } - int getFlexibility() { + final int getFlexibility() { return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH; } @@ -2143,7 +2231,7 @@ public class GridLayout extends ViewGroup { * @param alignment the alignment */ public static Spec spec(int start, int size, Alignment alignment) { - return new Spec(start, size, alignment); + return new Spec(start != UNDEFINED, start, size, alignment); } /** @@ -2246,7 +2334,7 @@ public class GridLayout extends ViewGroup { } } - private static final Alignment UNDEFINED_ALIGNMENT = new Alignment() { + static final Alignment UNDEFINED_ALIGNMENT = new Alignment() { public int getAlignmentValue(View view, int viewSize) { return UNDEFINED; } @@ -2367,7 +2455,7 @@ public class GridLayout extends ViewGroup { } }; - private static boolean canStretch(int flexibility) { + static boolean canStretch(int flexibility) { return (flexibility & CAN_STRETCH) != 0; } diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java index e571998..6aee5a0 100644 --- a/core/java/android/widget/OverScroller.java +++ b/core/java/android/widget/OverScroller.java @@ -584,10 +584,10 @@ public class OverScroller { // A device specific coefficient adjusted to physical values. private static float PHYSICAL_COEF; - private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9)); - private static final float INFLEXION = 0.4f; // Tension lines cross at (INFLEXION, 1) - private static final float START_TENSION = 1.0f; - private static final float END_TENSION = 0.6666f; + private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9)); + private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1) + private static final float START_TENSION = 0.5f; + private static final float END_TENSION = 1.0f; private static final float P1 = START_TENSION * INFLEXION; private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION); diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 4d45c2f..aac20c4 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -796,6 +796,21 @@ public class PopupWindow { * @param y the popup's y location offset */ public void showAtLocation(View parent, int gravity, int x, int y) { + showAtLocation(parent.getWindowToken(), gravity, x, y); + } + + /** + * Display the content view in a popup window at the specified location. + * + * @param token Window token to use for creating the new window + * @param gravity the gravity which controls the placement of the popup window + * @param x the popup's x location offset + * @param y the popup's y location offset + * + * @hide Internal use only. Applications should use + * {@link #showAtLocation(View, int, int, int)} instead. + */ + public void showAtLocation(IBinder token, int gravity, int x, int y) { if (isShowing() || mContentView == null) { return; } @@ -805,7 +820,7 @@ public class PopupWindow { mIsShowing = true; mIsDropdown = false; - WindowManager.LayoutParams p = createPopupLayout(parent.getWindowToken()); + WindowManager.LayoutParams p = createPopupLayout(token); p.windowAnimations = computeAnimationResource(); preparePopup(p); diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 6edfd59..12a93ac 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -212,6 +212,11 @@ public class RelativeLayout extends ViewGroup { * Describes how the child views are positioned. Defaults to * <code>Gravity.LEFT | Gravity.TOP</code>. * + * <p>Note that since RelativeLayout considers the positioning of each child + * relative to one another to be significant, setting gravity will affect + * the positioning of all children as a single unit within the parent. + * This happens after children have been relatively positioned.</p> + * * @param gravity See {@link android.view.Gravity} * * @see #setHorizontalGravity(int) diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d680f36..af820ac 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8944,14 +8944,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isPassword = hasPasswordTransformationMethod(); if (!isPassword) { - CharSequence text = getText(); + CharSequence text = getTextForAccessibility(); if (TextUtils.isEmpty(text)) { - text = getHint(); - } - if (TextUtils.isEmpty(text)) { - text = getContentDescription(); - } - if (!TextUtils.isEmpty(text)) { event.getText().add(text); } } @@ -8977,7 +8971,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isPassword = hasPasswordTransformationMethod(); if (!isPassword) { - info.setText(getText()); + info.setText(getTextForAccessibility()); } info.setPassword(isPassword); } @@ -8993,6 +8987,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.sendAccessibilityEvent(eventType); } + /** + * Gets the text reported for accessibility purposes. It is the + * text if not empty or the hint. + * + * @return The accessibility text. + */ + private CharSequence getTextForAccessibility() { + CharSequence text = getText(); + if (TextUtils.isEmpty(text)) { + text = getHint(); + } + return text; + } + void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, int fromIndex, int removedCount, int addedCount) { AccessibilityEvent event = |