diff options
Diffstat (limited to 'core/java')
39 files changed, 827 insertions, 490 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/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java index 10386f8..4fe54c0 100644 --- a/core/java/android/inputmethodservice/Keyboard.java +++ b/core/java/android/inputmethodservice/Keyboard.java @@ -144,6 +144,8 @@ public class Keyboard { /** Number of key widths from current touch point to search for nearest keys. */ private static float SEARCH_DISTANCE = 1.8f; + private ArrayList<Row> rows = new ArrayList<Row>(); + /** * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. * Some of the key size defaults can be overridden per row from what the {@link Keyboard} @@ -164,6 +166,9 @@ public class Keyboard { public int defaultHorizontalGap; /** Vertical gap following this row. */ public int verticalGap; + + ArrayList<Key> mKeys = new ArrayList<Key>(); + /** * Edge flags for this row of keys. Possible values that can be assigned are * {@link Keyboard#EDGE_TOP EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM EDGE_BOTTOM} @@ -256,7 +261,7 @@ public class Keyboard { public CharSequence text; /** Popup characters */ public CharSequence popupCharacters; - + /** * Flags that specify the anchoring to edges of the keyboard for detecting touch events * that are just out of the boundary of the key. This is a bit mask of @@ -596,11 +601,44 @@ public class Keyboard { column++; x += key.width + key.gap; mKeys.add(key); + row.mKeys.add(key); if (x > mTotalWidth) { mTotalWidth = x; } } - mTotalHeight = y + mDefaultHeight; + mTotalHeight = y + mDefaultHeight; + rows.add(row); + } + + final void resize(int newWidth, int newHeight) { + int numRows = rows.size(); + for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) { + Row row = rows.get(rowIndex); + int numKeys = row.mKeys.size(); + int totalGap = 0; + int totalWidth = 0; + for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) { + Key key = row.mKeys.get(keyIndex); + if (keyIndex > 0) { + totalGap += key.gap; + } + totalWidth += key.width; + } + if (totalGap + totalWidth > newWidth) { + int x = 0; + float scaleFactor = (float)(newWidth - totalGap) / totalWidth; + for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) { + Key key = row.mKeys.get(keyIndex); + key.width *= scaleFactor; + key.x = x; + x += key.width + key.gap; + } + } + } + mTotalWidth = newWidth; + // TODO: This does not adjust the vertical placement according to the new size. + // The main problem in the previous code was horizontal placement/size, but we should + // also recalculate the vertical sizes/positions when we get this resize call. } public List<Key> getKeys() { @@ -749,7 +787,7 @@ public class Keyboard { Row currentRow = null; Resources res = context.getResources(); boolean skipRow = false; - + try { int event; while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) { @@ -759,6 +797,7 @@ public class Keyboard { inRow = true; x = 0; currentRow = createRowFromXml(res, parser); + rows.add(currentRow); skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode; if (skipRow) { skipToEndOfRow(parser); @@ -781,6 +820,7 @@ public class Keyboard { } else if (key.codes[0] == KEYCODE_ALT) { mModifierKeys.add(key); } + currentRow.mKeys.add(key); } else if (TAG_KEYBOARD.equals(tag)) { parseKeyboardAttributes(res, parser); } diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index 05444f6..1119c1e 100644 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -376,6 +376,7 @@ public class KeyboardView extends View implements View.OnClickListener { initGestureDetector(); } + private void initGestureDetector() { mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { @Override @@ -615,6 +616,9 @@ public class KeyboardView extends View implements View.OnClickListener { @Override public void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); + if (mKeyboard != null) { + mKeyboard.resize(w, h); + } // Release the buffer, if any and it will be reallocated on the next draw mBuffer = null; } 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/text/method/Touch.java b/core/java/android/text/method/Touch.java index 3f9b945..106a801 100644 --- a/core/java/android/text/method/Touch.java +++ b/core/java/android/text/method/Touch.java @@ -35,44 +35,39 @@ public class Touch { * Y position. */ public static void scrollTo(TextView widget, Layout layout, int x, int y) { - int padding = widget.getTotalPaddingTop() + - widget.getTotalPaddingBottom(); - int top = layout.getLineForVertical(y); - int bottom = layout.getLineForVertical(y + widget.getHeight() - - padding); + final int verticalPadding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom(); + final int top = layout.getLineForVertical(y); + final int bottom = layout.getLineForVertical(y + widget.getHeight() - verticalPadding); int left = Integer.MAX_VALUE; int right = 0; - Alignment a = null; - boolean ltr = true; + Alignment a = layout.getParagraphAlignment(top); + boolean ltr = layout.getParagraphDirection(top) > 0; for (int i = top; i <= bottom; i++) { left = (int) Math.min(left, layout.getLineLeft(i)); right = (int) Math.max(right, layout.getLineRight(i)); - - if (a == null) { - a = layout.getParagraphAlignment(i); - ltr = layout.getParagraphDirection(i) > 0; - } } - padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); - int width = widget.getWidth(); - int diff = 0; + final int hoizontalPadding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); + final int availableWidth = widget.getWidth() - hoizontalPadding; + final int actualWidth = right - left; - // align_opposite does NOT mean align_right, we need the paragraph - // direction to resolve it to left or right - if (right - left < width - padding) { + if (actualWidth < availableWidth) { if (a == Alignment.ALIGN_CENTER) { - diff = (width - padding - (right - left)) / 2; - } else if (ltr == (a == Alignment.ALIGN_OPPOSITE)) { - diff = width - padding - (right - left); + x = left - ((availableWidth - actualWidth) / 2); + } else if ((ltr && (a == Alignment.ALIGN_OPPOSITE)) || (a == Alignment.ALIGN_RIGHT)) { + // align_opposite does NOT mean align_right, we need the paragraph + // direction to resolve it to left or right + x = left - (availableWidth - actualWidth); + } else { + x = left; } + } else { + x = Math.min(x, right - availableWidth); + x = Math.max(x, left); } - x = Math.min(x, right - (width - padding) - diff); - x = Math.max(x, left - diff); - widget.scrollTo(x, y); } diff --git a/core/java/android/view/ActionProvider.java b/core/java/android/view/ActionProvider.java index 5601dc5..ed976ab 100644 --- a/core/java/android/view/ActionProvider.java +++ b/core/java/android/view/ActionProvider.java @@ -58,6 +58,7 @@ import android.content.Context; * @see MenuItem#getActionProvider() */ public abstract class ActionProvider { + private SubUiVisibilityListener mSubUiVisibilityListener; /** * Creates a new instance. @@ -138,4 +139,31 @@ public abstract class ActionProvider { */ public void onPrepareSubMenu(SubMenu subMenu) { } + + /** + * Notify the system that the visibility of an action view's sub-UI such as + * an anchored popup has changed. This will affect how other system + * visibility notifications occur. + * + * @hide Pending future API approval + */ + public void subUiVisibilityChanged(boolean isVisible) { + if (mSubUiVisibilityListener != null) { + mSubUiVisibilityListener.onSubUiVisibilityChanged(isVisible); + } + } + + /** + * @hide Internal use only + */ + public void setSubUiVisibilityListener(SubUiVisibilityListener listener) { + mSubUiVisibilityListener = listener; + } + + /** + * @hide Internal use only + */ + public interface SubUiVisibilityListener { + public void onSubUiVisibilityChanged(boolean isVisible); + } } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0dc781f..55c821d 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; @@ -162,15 +163,13 @@ interface IWindowManager // These can only be called with the SET_ORIENTATION permission. /** - * Change the current screen rotation, constants as per - * {@link android.view.Surface}. - * @param rotation the intended rotation. + * Update the current screen rotation based on the current state of + * the world. * @param alwaysSendConfiguration Flag to force a new configuration to * be evaluated. This can be used when there are other parameters in * configuration that are changing. - * @param animFlags Animation flags as per {@link android.view.Surface}. */ - void setRotation(int rotation, boolean alwaysSendConfiguration, int animFlags); + void updateRotation(boolean alwaysSendConfiguration); /** * Retrieve the current screen orientation, constants as per @@ -220,7 +219,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/Surface.java b/core/java/android/view/Surface.java index 3880bc4..64d3d31 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -207,9 +207,6 @@ public class Surface implements Parcelable { /** Enable dithering when compositing this surface @hide */ public static final int SURFACE_DITHER = 0x04; - - /** Disable the orientation animation @hide */ - public static final int FLAGS_ORIENTATION_ANIMATION_DISABLE = 0x000000001; // The mSurfaceControl will only be present for Surfaces used by the window // server or system processes. When this class is parceled we defer to the @@ -393,7 +390,7 @@ public class Surface implements Parcelable { * set the orientation of the given display. * @param display * @param orientation - * @param flags + * @param flags Currently unused, set to 0. * @hide */ public static native void setOrientation(int display, int orientation, int flags); 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..1dbb083 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -375,12 +375,6 @@ public interface WindowManagerPolicy { /** Screen turned off because of proximity sensor */ public final int OFF_BECAUSE_OF_PROX_SENSOR = 4; - /** - * Magic constant to {@link IWindowManager#setRotation} to not actually - * modify the rotation. - */ - public final int USE_LAST_ROTATION = -1000; - /** When not otherwise specified by the activity's screenOrientation, rotation should be * determined by the system (that is, using sensors). */ public final int USER_ROTATION_FREE = 0; @@ -772,15 +766,26 @@ public interface WindowManagerPolicy { */ public void screenTurnedOff(int why); + public interface ScreenOnListener { + void onScreenOn(); + }; + /** - * Called after the screen turns on. + * 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 screenTurnedOn(); + public void screenTurningOn(ScreenOnListener screenOnListener); /** - * Return whether the screen is currently on. + * Return whether the screen is about to turn on or is currently on. */ - public boolean isScreenOn(); + public boolean isScreenOnEarly(); + + /** + * Return whether the screen is fully turned on. + */ + public boolean isScreenOnFully(); /** * Tell the policy that the lid switch has changed state. @@ -845,22 +850,30 @@ public interface WindowManagerPolicy { public boolean inKeyguardRestrictedKeyInputMode(); /** - * Given an orientation constant - * ({@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE - * ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE} or - * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_PORTRAIT - * ActivityInfo.SCREEN_ORIENTATION_PORTRAIT}), return a surface - * rotation. + * Given an orientation constant, returns the appropriate surface rotation, + * taking into account sensors, docking mode, rotation lock, and other factors. + * + * @param orientation An orientation constant, such as + * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. + * @param lastRotation The most recently used rotation. + * @return The surface rotation to use. */ - public int rotationForOrientationLw(int orientation, int lastRotation, - boolean displayEnabled); - + public int rotationForOrientationLw(int orientation, int lastRotation); + /** - * Return the currently locked screen rotation, if any. Return - * Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180, or - * Surface.ROTATION_270 if locked; return -1 if not locked. + * Given an orientation constant and a rotation, returns true if the rotation + * has compatible metrics to the requested orientation. For example, if + * the application requested landscape and got seascape, then the rotation + * has compatible metrics; if the application requested portrait and got landscape, + * then the rotation has incompatible metrics; if the application did not specify + * a preference, then anything goes. + * + * @param orientation An orientation constant, such as + * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. + * @param rotation The rotation to check. + * @return True if the rotation is compatible with the requested orientation. */ - public int getLockedRotationLw(); + public boolean rotationHasCompatibleMetricsLw(int orientation, int rotation); /** * Called when the system is mostly done booting to determine whether diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java index 76b47ca..726bf4a 100755 --- a/core/java/android/view/WindowOrientationListener.java +++ b/core/java/android/view/WindowOrientationListener.java @@ -118,14 +118,13 @@ public abstract class WindowOrientationListener { /** * Gets the current orientation. - * @param lastRotation - * @return + * @return The current rotation, or -1 if unknown. */ - public int getCurrentRotation(int lastRotation) { + public int getCurrentRotation() { if (mEnabled) { - return mSensorEventListener.getCurrentRotation(lastRotation); + return mSensorEventListener.getCurrentRotation(); } - return lastRotation; + return -1; } /** @@ -342,8 +341,8 @@ public abstract class WindowOrientationListener { mOrientationListener = orientationListener; } - public int getCurrentRotation(int lastRotation) { - return mRotation != ROTATION_UNKNOWN ? mRotation : lastRotation; + public int getCurrentRotation() { + return mRotation; // may be -1, if unknown } @Override diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java index 01587aa..b06c112 100644 --- a/core/java/android/view/textservice/TextServicesManager.java +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -223,7 +223,7 @@ public final class TextServicesManager { try { sService.setSpellCheckerEnabled(enabled); } catch (RemoteException e) { - Log.e(TAG, "Error in setSpellCheckerSubtype:" + e); + Log.e(TAG, "Error in setSpellCheckerEnabled:" + e); } } @@ -234,7 +234,7 @@ public final class TextServicesManager { try { return sService.isSpellCheckerEnabled(); } catch (RemoteException e) { - Log.e(TAG, "Error in setSpellCheckerSubtype:" + e); + Log.e(TAG, "Error in isSpellCheckerEnabled:" + e); return false; } } 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..47629c4 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() { @@ -7161,6 +7170,14 @@ public class WebView extends AbsoluteLayout } /** + * Return the overview scale of the WebView + * @return The overview scale. + */ + float getZoomOverviewScale() { + return mZoomManager.getZoomOverviewScale(); + } + + /** * @return TRUE if the WebView can be zoomed in. */ public boolean canZoomIn() { @@ -7194,10 +7211,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 +7319,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 +8210,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/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 48359d4..470e843 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -2512,10 +2512,13 @@ public final class WebViewCore { // called by JNI private void restoreScale(float scale, float textWrapScale) { if (mBrowserFrame.firstLayoutDone() == false) { - final float defaultScale = mWebView.getDefaultZoomScale(); - mRestoredScale = (scale <= 0.0) ? defaultScale : scale; + // If restored scale and textWrapScale are 0, set them to + // overview and reading level scale respectively. + mRestoredScale = (scale <= 0.0) + ? mWebView.getZoomOverviewScale() : scale; if (mSettings.getUseWideViewPort()) { - mRestoredTextWrapScale = (textWrapScale <= 0.0) ? defaultScale : textWrapScale; + mRestoredTextWrapScale = (textWrapScale <= 0.0) + ? mWebView.getReadingLevelScale() : textWrapScale; } } } diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 7ca6aeb..7f526e7 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -1128,12 +1128,6 @@ class ZoomManager { mTextWrapScale = Math.max(mTextWrapScale, overviewScale); } reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale); - } else { - // In case of restored scale, treat defaultScale as overview since - // it usually means the previous scale is not saved. - if (scale == mDefaultScale && settings.getLoadWithOverviewMode()) { - scale = overviewScale; - } } mInitialZoomOverview = settings.getLoadWithOverviewMode() && !exceedsMinScaleIncrement(scale, overviewScale); diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java index 312303d..c6e63c3 100644 --- a/core/java/android/widget/ActivityChooserView.java +++ b/core/java/android/widget/ActivityChooserView.java @@ -16,6 +16,8 @@ package android.widget; +import com.android.internal.R; + import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -23,19 +25,16 @@ import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.database.DataSetObserver; -import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.view.ActionProvider; import android.view.LayoutInflater; import android.view.View; -import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.ActivityChooserModel.ActivityChooserModelClient; -import com.android.internal.R; - /** * This class is a view for choosing an activity for handling a given {@link Intent}. * <p> @@ -107,6 +106,11 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod private final int mListPopupMaxWidth; /** + * The ActionProvider hosting this view, if applicable. + */ + ActionProvider mProvider; + + /** * Observer for the model data. */ private final DataSetObserver mModelDataSetOberver = new DataSetObserver() { @@ -131,6 +135,9 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod getListPopupWindow().dismiss(); } else { getListPopupWindow().show(); + if (mProvider != null) { + mProvider.subUiVisibilityChanged(true); + } } } } @@ -262,6 +269,14 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod } /** + * Set the provider hosting this view, if applicable. + * @hide Internal use only + */ + public void setProvider(ActionProvider provider) { + mProvider = provider; + } + + /** * Shows the popup window with activities. * * @return True if the popup was shown, false if already showing. @@ -289,9 +304,13 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod mAdapter.setMaxActivityCount(maxActivityCount); + final boolean defaultActivityButtonShown = + mDefaultActivityButton.getVisibility() == VISIBLE; + final int activityCount = mAdapter.getActivityCount(); + final int maxActivityCountOffset = defaultActivityButtonShown ? 1 : 0; if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED - && activityCount > maxActivityCount + 1) { + && activityCount > maxActivityCount + maxActivityCountOffset) { mAdapter.setShowFooterView(true); } else { mAdapter.setShowFooterView(false); @@ -299,14 +318,17 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod ListPopupWindow popupWindow = getListPopupWindow(); if (!popupWindow.isShowing()) { - if (mIsSelectingDefaultActivity) { - mAdapter.setShowDefaultActivity(true); + if (mIsSelectingDefaultActivity || !defaultActivityButtonShown) { + mAdapter.setShowDefaultActivity(true, defaultActivityButtonShown); } else { - mAdapter.setShowDefaultActivity(false); + mAdapter.setShowDefaultActivity(false, false); } final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth); popupWindow.setContentWidth(contentWidth); popupWindow.show(); + if (mProvider != null) { + mProvider.subUiVisibilityChanged(true); + } } } @@ -476,8 +498,10 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod mAdapter.getDataModel().setDefaultActivity(position); } } else { - // The first item in the model is default action => adjust index - Intent launchIntent = mAdapter.getDataModel().chooseActivity(position + 1); + // If the default target is not shown in the list, the first + // item in the model is default action => adjust index + position = mAdapter.getShowDefaultActivity() ? position : position + 1; + Intent launchIntent = mAdapter.getDataModel().chooseActivity(position); if (launchIntent != null) { mContext.startActivity(launchIntent); } @@ -523,6 +547,9 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod // PopUpWindow.OnDismissListener#onDismiss public void onDismiss() { notifyOnDismissListener(); + if (mProvider != null) { + mProvider.subUiVisibilityChanged(false); + } } private void notifyOnDismissListener() { @@ -553,6 +580,8 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod private boolean mShowDefaultActivity; + private boolean mHighlightDefaultActivity; + private boolean mShowFooterView; public void setDataModel(ActivityChooserModel dataModel) { @@ -640,7 +669,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod TextView titleView = (TextView) convertView.findViewById(R.id.title); titleView.setText(activity.loadLabel(packageManager)); // Highlight the default. - if (mShowDefaultActivity && position == 0) { + if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) { convertView.setActivated(true); } else { convertView.setActivated(false); @@ -709,11 +738,18 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod return mDataModel; } - public void setShowDefaultActivity(boolean showDefaultActivity) { - if (mShowDefaultActivity != showDefaultActivity) { + public void setShowDefaultActivity(boolean showDefaultActivity, + boolean highlightDefaultActivity) { + if (mShowDefaultActivity != showDefaultActivity + || mHighlightDefaultActivity != highlightDefaultActivity) { mShowDefaultActivity = showDefaultActivity; + mHighlightDefaultActivity = highlightDefaultActivity; notifyDataSetChanged(); } } + + public boolean getShowDefaultActivity() { + return mShowDefaultActivity; + } } } 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/MediaController.java b/core/java/android/widget/MediaController.java index 690164c..a63b8c8 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -299,6 +299,7 @@ public class MediaController extends FrameLayout { p.format = PixelFormat.TRANSLUCENT; p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; p.token = null; p.windowAnimations = 0; // android.R.style.DropDownAnimationDown; 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/PopupMenu.java b/core/java/android/widget/PopupMenu.java index 17512d8..6a6d767 100644 --- a/core/java/android/widget/PopupMenu.java +++ b/core/java/android/widget/PopupMenu.java @@ -157,6 +157,8 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback { * @hide */ public boolean onOpenSubMenu(MenuBuilder subMenu) { + if (subMenu == null) return false; + if (!subMenu.hasVisibleItems()) { return true; } 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/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java index 6e29024..3627890 100644 --- a/core/java/android/widget/ShareActionProvider.java +++ b/core/java/android/widget/ShareActionProvider.java @@ -169,6 +169,7 @@ public class ShareActionProvider extends ActionProvider { mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true); Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId); activityChooserView.setExpandActivityOverflowButtonDrawable(drawable); + activityChooserView.setProvider(this); return activityChooserView; } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d680f36..8db6592 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8944,13 +8944,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isPassword = hasPasswordTransformationMethod(); if (!isPassword) { - CharSequence text = getText(); - if (TextUtils.isEmpty(text)) { - text = getHint(); - } - if (TextUtils.isEmpty(text)) { - text = getContentDescription(); - } + CharSequence text = getTextForAccessibility(); 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 = diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index fba6a5a..0db1ccc 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -24,6 +24,7 @@ import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; import android.util.SparseBooleanArray; +import android.view.ActionProvider; import android.view.MenuItem; import android.view.SoundEffectConstants; import android.view.View; @@ -40,7 +41,8 @@ import java.util.ArrayList; /** * MenuPresenter for building action menus as seen in the action bar and action modes. */ -public class ActionMenuPresenter extends BaseMenuPresenter { +public class ActionMenuPresenter extends BaseMenuPresenter + implements ActionProvider.SubUiVisibilityListener { private static final String TAG = "ActionMenuPresenter"; private View mOverflowButton; @@ -187,6 +189,17 @@ public class ActionMenuPresenter extends BaseMenuPresenter { public void updateMenuView(boolean cleared) { super.updateMenuView(cleared); + if (mMenu != null) { + final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems(); + final int count = actionItems.size(); + for (int i = 0; i < count; i++) { + final ActionProvider provider = actionItems.get(i).getActionProvider(); + if (provider != null) { + provider.setSubUiVisibilityListener(this); + } + } + } + final boolean hasOverflow = mReserveOverflow && mMenu != null && mMenu.getNonActionItems().size() > 0; if (hasOverflow) { @@ -483,6 +496,16 @@ public class ActionMenuPresenter extends BaseMenuPresenter { } } + @Override + public void onSubUiVisibilityChanged(boolean isVisible) { + if (isVisible) { + // Not a submenu, but treat it like one. + super.onSubMenuSelected(null); + } else { + mMenu.close(false); + } + } + private static class SavedState implements Parcelable { public int openSubMenuId; @@ -590,7 +613,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter { @Override public void onDismiss() { super.onDismiss(); - mSubMenu.close(); mActionButtonPopup = null; mOpenSubMenuId = 0; } @@ -600,12 +622,17 @@ public class ActionMenuPresenter extends BaseMenuPresenter { @Override public boolean onOpenSubMenu(MenuBuilder subMenu) { + if (subMenu == null) return false; + mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); return false; } @Override public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + if (menu instanceof SubMenuBuilder) { + ((SubMenuBuilder) menu).getRootMenu().close(false); + } } } diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java index d1b1dae..24ddad6 100644 --- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java @@ -187,7 +187,9 @@ public class IconMenuPresenter extends BaseMenuPresenter { @Override public boolean onOpenSubMenu(MenuBuilder subMenu) { - mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); + if (subMenu != null) { + mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); + } return false; } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index e3a4df9..19dc42b 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -756,24 +756,36 @@ public class LockPatternUtils { } /** - * @return Whether the lock password is enabled. + * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak */ public boolean isLockPasswordEnabled() { long mode = getLong(PASSWORD_TYPE_KEY, 0); - return savedPasswordExists() && - (mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC - || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC - || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC - || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX); + long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0); + final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC + || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC + || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC + || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; + final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC + || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC + || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC + || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; + + return savedPasswordExists() && (passwordEnabled || + (isBiometricEnabled() && backupEnabled)); } /** - * @return Whether the lock pattern is enabled. + * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak */ public boolean isLockPatternEnabled() { + final boolean backupEnabled = + getLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) + == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; + return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED) - && getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) - == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; + && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) + == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING || + (isBiometricEnabled() && backupEnabled)); } /** @@ -923,8 +935,7 @@ public class LockPatternUtils { || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists() - || isPassword && savedPasswordExists() - || usingBiometricWeak() && isBiometricEnabled(); + || isPassword && savedPasswordExists(); return secure; } diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java index c03f91c..1b5112f 100644 --- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java +++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java @@ -114,6 +114,13 @@ public class MultiWaveView extends View { } }; + private AnimatorListener mResetListenerWithPing = new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animator) { + ping(); + switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY); + } + }; + private AnimatorUpdateListener mUpdateListener = new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { invalidateGlobalRegion(mHandleDrawable); @@ -421,7 +428,7 @@ public class MultiWaveView extends View { "x", mWaveCenterX, "y", mWaveCenterY, "onUpdate", mUpdateListener, - "onComplete", mResetListener); + "onComplete", mResetListenerWithPing); } setGrabbedState(OnTriggerListener.NO_HANDLE); diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java index 9f6ab31..8445ad1 100644 --- a/core/java/com/android/server/NetworkManagementSocketTagger.java +++ b/core/java/com/android/server/NetworkManagementSocketTagger.java @@ -75,30 +75,20 @@ public final class NetworkManagementSocketTagger extends SocketTagger { Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid); } - try { - // TODO: skip tagging when options would be no-op - tagSocketFd(fd, options.statsTag, options.statsUid); - } catch (IOException e) { - throw new SocketException("Problem tagging socket", e); - } + // TODO: skip tagging when options would be no-op + tagSocketFd(fd, options.statsTag, options.statsUid); } - private void tagSocketFd(FileDescriptor fd, int tag, int uid) throws IOException { - final int fdNum = fd.getInt$(); - if (fdNum == -1 || (tag == -1 && uid == -1)) return; - - String cmd = "t " + fdNum; - if (tag == -1) { - // Case where just the uid needs adjusting. But probably the caller - // will want to track his own name here, just in case. - cmd += " 0"; - } else { - cmd += " " + tagToKernel(tag); - } - if (uid != -1) { - cmd += " " + uid; + private void tagSocketFd(FileDescriptor fd, int tag, int uid) { + int errno; + if (tag == -1 && uid == -1) return; + + errno = native_tagSocketFd(fd, tag, uid); + if (errno < 0) { + Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " + + tag + ", " + + + uid + ") failed with errno" + errno); } - internalModuleCtrl(cmd); } @Override @@ -106,19 +96,18 @@ public final class NetworkManagementSocketTagger extends SocketTagger { if (LOGD) { Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); } - try { - unTagSocketFd(fd); - } catch (IOException e) { - throw new SocketException("Problem untagging socket", e); - } + unTagSocketFd(fd); } - private void unTagSocketFd(FileDescriptor fd) throws IOException { - int fdNum = fd.getInt$(); + private void unTagSocketFd(FileDescriptor fd) { final SocketTags options = threadSocketTags.get(); - if (fdNum == -1 || (options.statsTag == -1 && options.statsUid == -1)) return; - String cmd = "u " + fdNum; - internalModuleCtrl(cmd); + int errno; + if (options.statsTag == -1 && options.statsUid == -1) return; + + errno = native_untagSocketFd(fd); + if (errno < 0) { + Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); + } } public static class SocketTags { @@ -127,69 +116,20 @@ public final class NetworkManagementSocketTagger extends SocketTagger { } public static void setKernelCounterSet(int uid, int counterSet) { - final StringBuilder command = new StringBuilder(); - command.append("s ").append(counterSet).append(" ").append(uid); - try { - internalModuleCtrl(command.toString()); - } catch (IOException e) { - Slog.w(TAG, "problem changing counter set for uid " + uid + " : " + e); + int errno = native_setCounterSet(counterSet, uid); + if (errno < 0) { + Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno " + errno); } } public static void resetKernelUidStats(int uid) { - final StringBuilder command = new StringBuilder(); - command.append("d 0 ").append(uid); - try { - internalModuleCtrl(command.toString()); - } catch (IOException e) { - Slog.w(TAG, "problem clearing counters for uid " + uid + " : " + e); + int errno = native_deleteTagData(0, uid); + if (errno < 0) { + Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno); } } /** - * Sends commands to the kernel netfilter module. - * - * @param cmd command string for the qtaguid netfilter module. May not be null. - * <p>Supports: - * <ul><li>tag a socket:<br> - * <code>t <i>sock_fd</i> <i>acct_tag</i> [<i>uid_in_case_caller_is_acting_on_behalf_of</i>]</code><br> - * <code>*_tag</code> defaults to default_policy_tag_from_uid(uid_of_caller)<br> - * <code>acct_tag</code> is either 0 or greater that 2^32.<br> - * <code>uid_*</code> is only settable by privileged UIDs (DownloadManager,...) - * </li> - * <li>untag a socket, preserving counters:<br> - * <code>u <i>sock_fd</i></code> - * </li></ul> - * <p>Notes:<br> - * <ul><li><i>sock_fd</i> is withing the callers process space.</li> - * <li><i>*_tag</i> are 64bit values</li></ul> - * - */ - private static void internalModuleCtrl(String cmd) throws IOException { - if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return; - - // TODO: migrate to native library for tagging commands - FileOutputStream procOut = null; - try { - procOut = new FileOutputStream("/proc/net/xt_qtaguid/ctrl"); - procOut.write(cmd.getBytes(Charsets.US_ASCII)); - } finally { - IoUtils.closeQuietly(procOut); - } - } - - /** - * Convert {@link Integer} tag to {@code /proc/} format. Assumes unsigned - * base-10 format like {@code 2147483647}. Currently strips signed bit to - * avoid using {@link BigInteger}. - */ - public static String tagToKernel(int tag) { - // TODO: eventually write in hex, since that's what proc exports - // TODO: migrate to direct integer instead of odd shifting - return Long.toString((((long) tag) << 32) & 0x7FFFFFFF00000000L); - } - - /** * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming * format like {@code 0x7fffffff00000000}. */ @@ -197,4 +137,9 @@ public final class NetworkManagementSocketTagger extends SocketTagger { // TODO: migrate to direct integer instead of odd shifting return (int) (Long.decode(string) >> 32); } + + private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); + private static native int native_untagSocketFd(FileDescriptor fd); + private static native int native_setCounterSet(int uid, int counterSetNum); + private static native int native_deleteTagData(int tag, int uid); } |