summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java15
-rw-r--r--core/java/android/app/ActionBar.java14
-rw-r--r--core/java/android/app/Fragment.java5
-rw-r--r--core/java/android/app/FragmentManager.java2
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java63
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl4
-rw-r--r--core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl27
-rw-r--r--core/java/android/content/Context.java12
-rw-r--r--core/java/android/content/Loader.java2
-rw-r--r--core/java/android/content/SyncManager.java20
-rw-r--r--core/java/android/hardware/Camera.java195
-rw-r--r--core/java/android/net/INetworkPolicyManager.aidl3
-rw-r--r--core/java/android/net/NetworkPolicy.java31
-rw-r--r--core/java/android/net/NetworkPolicyManager.java22
-rw-r--r--core/java/android/os/INetworkManagementService.aidl21
-rw-r--r--core/java/android/os/IPowerManager.aidl3
-rw-r--r--core/java/android/provider/CallLog.java1
-rw-r--r--core/java/android/provider/ContactsContract.java33
-rw-r--r--core/java/android/provider/VoicemailContract.java6
-rw-r--r--core/java/android/server/BluetoothAdapterStateMachine.java234
-rw-r--r--core/java/android/server/BluetoothEventLoop.java4
-rwxr-xr-xcore/java/android/server/BluetoothService.java91
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java2
-rw-r--r--core/java/android/view/Display.java163
-rw-r--r--core/java/android/view/GLES20Canvas.java17
-rw-r--r--core/java/android/view/GLES20RecordingCanvas.java2
-rw-r--r--core/java/android/view/GLES20RenderLayer.java1
-rw-r--r--core/java/android/view/HardwareRenderer.java98
-rw-r--r--core/java/android/view/IWindowManager.aidl1
-rw-r--r--core/java/android/view/MotionEvent.java41
-rw-r--r--core/java/android/view/View.java37
-rw-r--r--core/java/android/view/ViewGroup.java5
-rw-r--r--core/java/android/view/ViewRootImpl.java22
-rw-r--r--core/java/android/webkit/DebugFlags.java2
-rw-r--r--core/java/android/webkit/WebTextView.java172
-rw-r--r--core/java/android/webkit/WebView.java73
-rw-r--r--core/java/android/widget/AbsListView.java94
-rw-r--r--core/java/android/widget/ActivityChooserView.java48
-rw-r--r--core/java/android/widget/FrameLayout.java17
-rw-r--r--core/java/android/widget/SearchView.java20
-rw-r--r--core/java/android/widget/TextView.java103
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java285
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java2
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuView.java22
-rw-r--r--core/java/com/android/internal/view/menu/MenuBuilder.java3
-rw-r--r--core/java/com/android/internal/view/menu/MenuItemImpl.java2
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java11
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java2
48 files changed, 1152 insertions, 901 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 68c9926..1e238f0 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -130,20 +130,11 @@ import android.view.accessibility.AccessibilityNodeInfo;
* For security purposes an accessibility service can retrieve only the content of the
* currently active window. The currently active window is defined as the window from
* which was fired the last event of the following types:
- * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START},
- * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END},
- * {@link AccessibilityEvent#TYPE_VIEW_CLICKED},
- * {@link AccessibilityEvent#TYPE_VIEW_FOCUSED},
+ * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
* {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
* {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
- * {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED},
- * {@link AccessibilityEvent#TYPE_VIEW_SELECTED},
- * {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED},
- * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
- * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED},
- * {@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED},
- * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}.
- * In other words, the active window is the one where the user interaction is taking place.
+ * In other words, the last window that was shown or the last window that the user has touched
+ * during touch exploration.
* </p>
* <p>
* The entry point for retrieving window content is through calling
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 36940c2..a217867 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -29,10 +29,16 @@ import android.view.Window;
import android.widget.SpinnerAdapter;
/**
- * This is the public interface to the contextual ActionBar.
- * The ActionBar acts as a replacement for the title bar in Activities.
- * It provides facilities for creating toolbar actions as well as
- * methods of navigating around an application.
+ * Acts as a replacement for the title bar in Activities.
+ * The action bar provides facilities for creating toolbar actions as well as
+ * methods of navigating the application.
+ * <p>By default, the action bar appears at the top of every activity, with the application icon on
+ * the left, followed by the activity title. Items from the activity's options menu are also
+ * accessible from the action bar.</p>
+ * <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link
+ * android.app.Activity#getActionBar getActionBar()}.</p>
+ * <p>For more information, read the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action
+ * Bar</a> developer guide.</p>
*/
public abstract class ActionBar {
/**
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index cb97c46..e2746d4 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -162,6 +162,9 @@ final class FragmentState implements Parcelable {
* constructor to instantiate it. If the empty constructor is not available,
* a runtime exception will occur in some cases during state restore.
*
+ * <p>For more documentation, also see the <a
+ * href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
+ *
* <p>Topics covered here:
* <ol>
* <li><a href="#OlderPlatforms">Older Platforms</a>
@@ -880,7 +883,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
public void setHasOptionsMenu(boolean hasMenu) {
if (mHasMenu != hasMenu) {
mHasMenu = hasMenu;
- if (isAdded() && !isHidden()) {
+ if (isAdded() && !isHidden() && isResumed()) {
mActivity.invalidateOptionsMenu();
}
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 789d3a6..24550c5 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -978,7 +978,7 @@ final class FragmentManagerImpl extends FragmentManager {
}
}
- if (mNeedMenuInvalidate && mActivity != null) {
+ if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) {
mActivity.invalidateOptionsMenu();
mNeedMenuInvalidate = false;
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b993bd8..ca6f085 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1143,6 +1143,69 @@ public final class BluetoothAdapter {
}
}
+ /**
+ * Enable control of the Bluetooth Adapter for a single application.
+ *
+ * <p>Some applications need to use Bluetooth for short periods of time to
+ * transfer data but don't want all the associated implications like
+ * automatic connection to headsets etc.
+ *
+ * <p> Multiple applications can call this. This is reference counted and
+ * Bluetooth disabled only when no one else is using it. There will be no UI
+ * shown to the user while bluetooth is being enabled. Any user action will
+ * override this call. For example, if user wants Bluetooth on and the last
+ * user of this API wanted to disable Bluetooth, Bluetooth will not be
+ * turned off.
+ *
+ * <p> This API is only meant to be used by internal applications. Third
+ * party applications but use {@link #enable} and {@link #disable} APIs.
+ *
+ * <p> If this API returns true, it means the callback will be called.
+ * The callback will be called with the current state of Bluetooth.
+ * If the state is not what was requested, an internal error would be the
+ * reason.
+ *
+ * @param on True for on, false for off.
+ * @param callback The callback to notify changes to the state.
+ * @hide
+ */
+ public boolean changeApplicationBluetoothState(boolean on,
+ BluetoothStateChangeCallback callback) {
+ if (callback == null) return false;
+
+ try {
+ return mService.changeApplicationBluetoothState(on, new
+ StateChangeCallbackWrapper(callback), new Binder());
+ } catch (RemoteException e) {
+ Log.e(TAG, "changeBluetoothState", e);
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ public interface BluetoothStateChangeCallback {
+ public void onBluetoothStateChange(boolean on);
+ }
+
+ /**
+ * @hide
+ */
+ public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
+ private BluetoothStateChangeCallback mCallback;
+
+ StateChangeCallbackWrapper(BluetoothStateChangeCallback
+ callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onBluetoothStateChange(boolean on) {
+ mCallback.onBluetoothStateChange(on);
+ }
+ }
+
private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
for (int i = 0; i < addresses.length; i++) {
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 183772d..be43c51 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothStateChangeCallback;
import android.bluetooth.IBluetoothHealthCallback;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHealthAppConfiguration;
@@ -52,6 +53,9 @@ interface IBluetooth
byte[] readOutOfBandData();
int getAdapterConnectionState();
+ boolean changeApplicationBluetoothState(boolean on,
+ in IBluetoothStateChangeCallback callback, in
+ IBinder b);
boolean createBond(in String address);
boolean createBondOutOfBand(in String address, in byte[] hash, in byte[] randomizer);
diff --git a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
new file mode 100644
index 0000000..feccdce
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+/**
+ * System private API for Bluetooth state change callback.
+ *
+ * {@hide}
+ */
+interface IBluetoothStateChangeCallback
+{
+ void onBluetoothStateChange(boolean on);
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index cdda910..2a02446 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -129,7 +129,7 @@ public abstract class Context {
/**
* Flag for {@link #bindService}: don't allow this binding to raise
* the target service's process to the foreground scheduling priority.
- * It will still be raised to the at least the same memory priority
+ * It will still be raised to at least the same memory priority
* as the client (so that its process will not be killable in any
* situation where the client is not killable), but for CPU scheduling
* purposes it may be left in the background. This only has an impact
@@ -138,6 +138,16 @@ public abstract class Context {
*/
public static final int BIND_NOT_FOREGROUND = 0x0004;
+ /**
+ * Flag for {@link #bindService}: allow the process hosting the bound
+ * service to go through its normal memory management. It will be
+ * treated more like a running service, allowing the system to
+ * (temporarily) expunge the process if low on memory or for some other
+ * whim it may have.
+ * @hide
+ */
+ public static final int BIND_ALLOW_OOM_MANAGEMENT = 0x0008;
+
/** Return an AssetManager instance for your application's package. */
public abstract AssetManager getAssets();
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index 4e70b74..368c33e 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -40,6 +40,8 @@ import java.io.PrintWriter;
*
* <p>Most implementations should not derive directly from this class, but
* instead inherit from {@link AsyncTaskLoader}.</p>
+ * <p>For more information, see the <a
+ * href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> developer guide.</p>
*
* @param <D> The result returned when the load is complete
*/
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 2cb8a86..5be6ec1 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -1691,12 +1691,28 @@ public class SyncManager implements OnAccountsUpdateListener {
continue;
}
- // skip the sync if it isn't manual and auto sync or
- // background data usage is disabled
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(op.authority, op.account.type));
+
+ // only proceed if network is connected for requesting UID
+ final boolean uidNetworkConnected;
+ if (syncAdapterInfo != null) {
+ final NetworkInfo networkInfo = getConnectivityManager()
+ .getActiveNetworkInfoForUid(syncAdapterInfo.uid);
+ uidNetworkConnected = networkInfo != null && networkInfo.isConnected();
+ } else {
+ uidNetworkConnected = false;
+ }
+
+ // skip the sync if it isn't manual, and auto sync or
+ // background data usage is disabled or network is
+ // disconnected for the target UID.
if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
&& (syncableState > 0)
&& (!masterSyncAutomatically
|| !backgroundDataUsageAllowed
+ || !uidNetworkConnected
|| !mSyncStorageEngine.getSyncAutomatically(
op.account, op.authority))) {
operationIterator.remove();
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index a168260..d6dbc15 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -19,6 +19,7 @@ package android.hardware;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.graphics.ImageFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Handler;
@@ -35,6 +36,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
+
/**
* The Camera class is used to set image capture settings, start/stop preview,
* snap pictures, and retrieve frames for encoding for video. This class is a
@@ -128,7 +130,9 @@ public class Camera {
private static final int CAMERA_MSG_POSTVIEW_FRAME = 0x040;
private static final int CAMERA_MSG_RAW_IMAGE = 0x080;
private static final int CAMERA_MSG_COMPRESSED_IMAGE = 0x100;
- private static final int CAMERA_MSG_ALL_MSGS = 0x1FF;
+ private static final int CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x200;
+ private static final int CAMERA_MSG_FACE = 0x400;
+ private static final int CAMERA_MSG_ALL_MSGS = 0x4FF;
private int mNativeContext; // accessed by native methods
private EventHandler mEventHandler;
@@ -139,9 +143,11 @@ public class Camera {
private PictureCallback mPostviewCallback;
private AutoFocusCallback mAutoFocusCallback;
private OnZoomChangeListener mZoomListener;
+ private FaceDetectionListener mFaceListener;
private ErrorCallback mErrorCallback;
private boolean mOneShot;
private boolean mWithBuffer;
+ private boolean mFaceDetectionRunning = false;
/**
* Broadcast Action: A new picture is taken by the camera, and the entry of
@@ -160,6 +166,25 @@ public class Camera {
public static final String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
/**
+ * Hardware face detection. It does not use much CPU.
+ *
+ * @see #startFaceDetection(int)
+ * @see Parameters#getMaxNumDetectedFaces(int)
+ * @see #CAMERA_FACE_DETECTION_SW
+ * @hide
+ */
+ public static final int CAMERA_FACE_DETECTION_HW = 0;
+
+ /**
+ * Software face detection. It uses some CPU. Applications must use
+ * {@link #setPreviewTexture(SurfaceTexture)} for preview in this mode.
+ *
+ * @see #CAMERA_FACE_DETECTION_HW
+ * @hide
+ */
+ public static final int CAMERA_FACE_DETECTION_SW = 1;
+
+ /**
* Returns the number of physical cameras available on this device.
*/
public native static int getNumberOfCameras();
@@ -295,6 +320,7 @@ public class Camera {
*/
public final void release() {
native_release();
+ mFaceDetectionRunning = false;
}
/**
@@ -460,7 +486,12 @@ public class Camera {
* Stops capturing and drawing preview frames to the surface, and
* resets the camera for a future call to {@link #startPreview()}.
*/
- public native final void stopPreview();
+ public final void stopPreview() {
+ _stopPreview();
+ mFaceDetectionRunning = false;
+ }
+
+ private native final void _stopPreview();
/**
* Return current preview state.
@@ -690,6 +721,12 @@ public class Camera {
}
return;
+ case CAMERA_MSG_FACE:
+ if (mFaceListener != null) {
+ mFaceListener.onFaceDetection((FaceMetadata[])msg.obj, mCamera);
+ }
+ return;
+
case CAMERA_MSG_ERROR :
Log.e(TAG, "Error " + msg.arg1);
if (mErrorCallback != null) {
@@ -1031,6 +1068,139 @@ public class Camera {
mZoomListener = listener;
}
+ /**
+ * Callback interface for face detected in the preview frame.
+ *
+ * @hide
+ */
+ public interface FaceDetectionListener
+ {
+ /**
+ * Notify the listener of the detected faces in the preview frame.
+ *
+ * @param faceMetadata the face information. The list is sorted by the
+ * score. The highest score is the first element.
+ * @param camera the Camera service object
+ */
+ void onFaceDetection(FaceMetadata[] faceMetadata, Camera camera);
+ }
+
+ /**
+ * Registers a listener to be notified about the face detected of the
+ * preview frame.
+ *
+ * @param listener the listener to notify
+ * @see #startFaceDetection(int)
+ * @hide
+ */
+ public final void setFaceDetectionListener(FaceDetectionListener listener)
+ {
+ mFaceListener = listener;
+ }
+
+ /**
+ * Start the face detection. This should be called after preview is started.
+ * The camera will notify {@link FaceDetectionListener} of the detected
+ * faces in the preview frame. The detected faces may be the same as the
+ * previous ones. Applications should call {@link #stopFaceDetection} to
+ * stop the face detection. This method is supported if {@link
+ * Parameters#getMaxNumDetectedFaces(int)} returns a number larger than 0.
+ * Hardware and software face detection cannot be used at the same time.
+ * If the face detection has started, apps should not call this again.
+ *
+ * In hardware face detection mode, {@link Parameters#setWhiteBalance(String)},
+ * {@link Parameters#setFocusAreas(List)}, and {@link Parameters#setMeteringAreas(List)}
+ * have no effect.
+ *
+ * @param type face detection type. This can be either {@link
+ * #CAMERA_FACE_DETECTION_HW} or {@link #CAMERA_FACE_DETECTION_SW}
+ * @throws IllegalArgumentException if the face detection type is
+ * unsupported or invalid.
+ * @throws RuntimeException if the method fails or the face detection is
+ * already running.
+ * @see #CAMERA_FACE_DETECTION_HW
+ * @see #CAMERA_FACE_DETECTION_SW
+ * @see FaceDetectionListener
+ * @see #stopFaceDetection()
+ * @see Parameters#getMaxNumDetectedFaces(int)
+ * @hide
+ */
+ public final void startFaceDetection(int type) {
+ if (type != CAMERA_FACE_DETECTION_HW && type != CAMERA_FACE_DETECTION_SW) {
+ throw new IllegalArgumentException("Invalid face detection type " + type);
+ }
+ if (mFaceDetectionRunning) {
+ throw new RuntimeException("Face detection is already running");
+ }
+ _startFaceDetection(type);
+ mFaceDetectionRunning = true;
+ }
+
+ /**
+ * Stop the face detection.
+ *
+ * @see #startFaceDetection(int)
+ * @hide
+ */
+ public final void stopFaceDetection() {
+ _stopFaceDetection();
+ mFaceDetectionRunning = false;
+ }
+
+ private native final void _startFaceDetection(int type);
+ private native final void _stopFaceDetection();
+
+ /**
+ * The information of a face.
+ *
+ * @hide
+ */
+ public static class FaceMetadata {
+ /**
+ * Bounds of the face. (-1000, -1000) represents the top-left of the
+ * camera field of view, and (1000, 1000) represents the bottom-right of
+ * the field of view. This is supported by both hardware and software
+ * face detection.
+ *
+ * @see #startFaceDetection(int)
+ */
+ Rect face;
+
+ /**
+ * The confidence level of the face. The range is 1 to 100. 100 is the
+ * highest confidence. This is supported by both hardware and software
+ * face detction.
+ *
+ * @see #startFaceDetection(int)
+ */
+ int score;
+
+ /**
+ * An unique id per face while the face is visible to the tracker. If
+ * the face leaves the field-of-view and comes back, it will get a new
+ * id. If the value is 0, id is not supported.
+ */
+ int id;
+
+ /**
+ * The coordinates of the center of the left eye. null if this is not
+ * supported.
+ */
+ Point leftEye;
+
+ /**
+ * The coordinates of the center of the right eye. null if this is not
+ * supported.
+ */
+ Point rightEye;
+
+ /**
+ * The coordinates of the center of the mouth. null if this is not
+ * supported.
+ */
+ Point mouth;
+ }
+
// Error codes match the enum in include/ui/Camera.h
/**
@@ -1295,6 +1465,8 @@ public class Camera {
private static final String KEY_VIDEO_SIZE = "video-size";
private static final String KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO =
"preferred-preview-size-for-video";
+ private static final String KEY_MAX_NUM_DETECTED_FACES_HW = "max-num-detected-faces-hw";
+ private static final String KEY_MAX_NUM_DETECTED_FACES_SW = "max-num-detected-faces-sw";
// Parameter key suffix for supported values.
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -2977,6 +3149,25 @@ public class Camera {
set(KEY_METERING_AREAS, meteringAreas);
}
+ /**
+ * Gets the maximum number of detected faces supported. This is the
+ * maximum length of the list returned from {@link FaceDetectionListener}.
+ * If the return value is 0, face detection of the specified type is not
+ * supported.
+ *
+ * @return the maximum number of detected face supported by the camera.
+ * @see #startFaceDetection(int)
+ * @hide
+ */
+ public int getMaxNumDetectedFaces(int type) {
+ if (type == CAMERA_FACE_DETECTION_HW) {
+ return getInt(KEY_MAX_NUM_DETECTED_FACES_HW, 0);
+ } else if (type == CAMERA_FACE_DETECTION_SW){
+ return getInt(KEY_MAX_NUM_DETECTED_FACES_SW, 0);
+ }
+ throw new IllegalArgumentException("Invalid face detection type " + type);
+ }
+
// Splits a comma delimited string to an ArrayList of String.
// Return null if the passing string is null or the size is 0.
private ArrayList<String> split(String str) {
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 82495e3..6fde746 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -18,6 +18,7 @@ package android.net;
import android.net.INetworkPolicyListener;
import android.net.NetworkPolicy;
+import android.net.NetworkTemplate;
/**
* Interface that creates and modifies network policy rules.
@@ -37,4 +38,6 @@ interface INetworkPolicyManager {
void setNetworkPolicies(in NetworkPolicy[] policies);
NetworkPolicy[] getNetworkPolicies();
+ void snoozePolicy(in NetworkTemplate template);
+
}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 52cab30..aaad8a1 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -21,6 +21,8 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Objects;
+
/**
* Policy for networks matching a {@link NetworkTemplate}, including usage cycle
* and limits to be enforced.
@@ -30,20 +32,21 @@ import android.os.Parcelable;
public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
public static final long WARNING_DISABLED = -1;
public static final long LIMIT_DISABLED = -1;
+ public static final long SNOOZE_NEVER = -1;
public final NetworkTemplate template;
public int cycleDay;
public long warningBytes;
public long limitBytes;
+ public long lastSnooze;
- // TODO: teach how to snooze limit for current cycle
-
- public NetworkPolicy(
- NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes) {
+ public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes,
+ long lastSnooze) {
this.template = checkNotNull(template, "missing NetworkTemplate");
this.cycleDay = cycleDay;
this.warningBytes = warningBytes;
this.limitBytes = limitBytes;
+ this.lastSnooze = lastSnooze;
}
public NetworkPolicy(Parcel in) {
@@ -51,6 +54,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
cycleDay = in.readInt();
warningBytes = in.readLong();
limitBytes = in.readLong();
+ lastSnooze = in.readLong();
}
/** {@inheritDoc} */
@@ -59,6 +63,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
dest.writeInt(cycleDay);
dest.writeLong(warningBytes);
dest.writeLong(limitBytes);
+ dest.writeLong(lastSnooze);
}
/** {@inheritDoc} */
@@ -80,9 +85,25 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastSnooze);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof NetworkPolicy) {
+ final NetworkPolicy other = (NetworkPolicy) obj;
+ return Objects.equal(template, other.template) && cycleDay == other.cycleDay
+ && warningBytes == other.warningBytes && limitBytes == other.limitBytes
+ && lastSnooze == other.lastSnooze;
+ }
+ return false;
+ }
+
+ @Override
public String toString() {
return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes="
- + warningBytes + ", limitBytes=" + limitBytes;
+ + warningBytes + ", limitBytes=" + limitBytes + ", lastSnooze=" + lastSnooze;
}
public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 593b2b7..1e9d813 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -52,26 +52,10 @@ public class NetworkPolicyManager {
private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
/**
- * {@link Intent} action launched when user selects {@link NetworkPolicy}
- * warning notification.
+ * {@link Intent} extra that indicates which {@link NetworkTemplate} rule it
+ * applies to.
*/
- public static final String ACTION_DATA_USAGE_WARNING =
- "android.intent.action.DATA_USAGE_WARNING";
-
- /**
- * {@link Intent} action launched when user selects {@link NetworkPolicy}
- * limit notification.
- */
- public static final String ACTION_DATA_USAGE_LIMIT =
- "android.intent.action.DATA_USAGE_LIMIT";
-
- /**
- * {@link Intent} extra included in {@link #ACTION_DATA_USAGE_WARNING} and
- * {@link #ACTION_DATA_USAGE_LIMIT} to indicate which
- * {@link NetworkTemplate} rule it applies to.
- */
- public static final String EXTRA_NETWORK_TEMPLATE =
- "android.intent.extra.NETWORK_TEMPLATE";
+ public static final String EXTRA_NETWORK_TEMPLATE = "android.net.NETWORK_TEMPLATE";
private INetworkPolicyManager mService;
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 1174e3b..3704248 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -212,7 +212,7 @@ interface INetworkManagementService
/**
* Set quota for an interface.
*/
- void setInterfaceQuota(String iface, long quota);
+ void setInterfaceQuota(String iface, long quotaBytes);
/**
* Remove quota for an interface.
@@ -220,6 +220,21 @@ interface INetworkManagementService
void removeInterfaceQuota(String iface);
/**
+ * Set alert for an interface; requires that iface already has quota.
+ */
+ void setInterfaceAlert(String iface, long alertBytes);
+
+ /**
+ * Remove alert for an interface.
+ */
+ void removeInterfaceAlert(String iface);
+
+ /**
+ * Set alert across all interfaces.
+ */
+ void setGlobalAlert(long alertBytes);
+
+ /**
* Control network activity of a UID over interfaces with a quota limit.
*/
void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
@@ -252,12 +267,12 @@ interface INetworkManagementService
void setDnsServersForInterface(String iface, in String[] servers);
/**
- * Flush the DNS cache associated with the default interface
+ * Flush the DNS cache associated with the default interface.
*/
void flushDefaultDnsCache();
/**
- * Flush the DNS cache associated with the specified interface
+ * Flush the DNS cache associated with the specified interface.
*/
void flushInterfaceDnsCache(String iface);
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 0067e94..9a53d76 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -20,12 +20,15 @@ package android.os;
import android.os.WorkSource;
/** @hide */
+
interface IPowerManager
{
+ // WARNING: changes in acquireWakeLock() signature must be reflected in IPowerManager.cpp/h
void acquireWakeLock(int flags, IBinder lock, String tag, in WorkSource ws);
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
void goToSleep(long time);
void goToSleepWithReason(long time, int reason);
+ // WARNING: changes in releaseWakeLock() signature must be reflected in IPowerManager.cpp/h
void releaseWakeLock(IBinder lock, int flags);
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index e23d6f3..b8ef7be 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -189,7 +189,6 @@ public class CallLog {
* Unlike the {@link #NEW} field, which requires the user to have acknowledged the
* existence of the entry, this implies the user has interacted with the entry.
* <P>Type: INTEGER (boolean)</P>
- * @hide
*/
public static final String IS_READ = "is_read";
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b2c1386..5765dde 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1973,6 +1973,16 @@ public final class ContactsContract {
public static final String DATA_SET = "data_set";
/**
+ * A concatenation of the account type and data set (delimited by a forward
+ * slash) - if the data set is empty, this will be the same as the account
+ * type. For applications that need to be aware of the data set, this can
+ * be used instead of account type to distinguish sets of data. This is
+ * never intended to be used for specifying accounts.
+ * @hide
+ */
+ public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set";
+
+ /**
* The aggregation mode for this contact.
* <P>Type: INTEGER</P>
*/
@@ -6444,6 +6454,16 @@ public final class ContactsContract {
public static final String DATA_SET = "data_set";
/**
+ * A concatenation of the account type and data set (delimited by a forward
+ * slash) - if the data set is empty, this will be the same as the account
+ * type. For applications that need to be aware of the data set, this can
+ * be used instead of account type to distinguish sets of data. This is
+ * never intended to be used for specifying accounts.
+ * @hide
+ */
+ public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set";
+
+ /**
* The display title of this group.
* <p>
* Type: TEXT
@@ -7871,6 +7891,19 @@ public final class ContactsContract {
* @hide
*/
public static final String ACCOUNT = "com.android.contacts.extra.ACCOUNT";
+
+ /**
+ * Used to specify the data set within the account in which to create the
+ * new contact.
+ * <p>
+ * This value is optional - if it is not specified, the contact will be
+ * created in the base account, with no data set.
+ * <p>
+ * Type: String
+ *
+ * @hide
+ */
+ public static final String DATA_SET = "com.android.contacts.extra.DATA_SET";
}
}
}
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 2e5a495..a31374f 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -123,14 +123,8 @@ public class VoicemailContract {
*/
public static final String DURATION = Calls.DURATION;
/**
- * Whether this is a new voicemail (i.e. has not been heard).
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String NEW = Calls.NEW;
- /**
* Whether this item has been read or otherwise consumed by the user.
* <P>Type: INTEGER (boolean)</P>
- * @hide
*/
public static final String IS_READ = Calls.IS_READ;
/**
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index ae91465..83f5a9f 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -17,11 +17,13 @@
package android.server;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.IBluetoothStateChangeCallback;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Message;
+import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
@@ -34,17 +36,18 @@ import java.io.PrintWriter;
/**
* Bluetooth Adapter StateMachine
* All the states are at the same level, ie, no hierarchy.
- * (BluetootOn)
- * | ^
- * TURN_OFF | | BECOME_PAIRABLE
- * AIRPLANE_MODE_ON | |
- * V |
- * (Switching)
- * | ^
- * BECOME_NON_PAIRABLE& | | TURN_ON(_CONTINUE)/TURN_ON_FOR_PRIVILEGED
- * ALL_DEVICES_DISCONNECTED | |
- * V |
- * (HotOff)
+ * (BluetootOn)<----------------------<-
+ * | ^ -------------------->- |
+ * | | | |
+ * TURN_OFF | | BECAME_PAIRABLE m1 | | USER_TURN_ON
+ * AIRPLANE_MODE_ON | | | |
+ * V | | |
+ * (Switching) (PerProcessState)
+ * | ^ | |
+ * BECAME_NON_PAIRABLE& | | TURN_ON(_CONTINUE) | |
+ * ALL_DEVICES_DISCONNECTED | | m2 | |
+ * V |------------------------< | BECAME_PAIRABLE
+ * (HotOff)---------------------------- PER_PROCESS_TURN_ON
* / ^
* / | SERVICE_RECORD_LOADED
* | |
@@ -55,6 +58,10 @@ import java.io.PrintWriter;
* V |
* (PowerOff) <----- initial state
*
+ * Legend:
+ * m1 = USER_TURN_OFF
+ * m2 = Transition to HotOff when number of process wanting BT on is 0.
+ * BECAME_NON_PAIRABLE will make the transition.
*/
final class BluetoothAdapterStateMachine extends StateMachine {
private static final String TAG = "BluetoothAdapterStateMachine";
@@ -63,24 +70,24 @@ final class BluetoothAdapterStateMachine extends StateMachine {
// Message(what) to take an action
//
// We get this message when user tries to turn on BT
- public static final int USER_TURN_ON = 1;
+ static final int USER_TURN_ON = 1;
// We get this message when user tries to turn off BT
- public static final int USER_TURN_OFF = 2;
+ static final int USER_TURN_OFF = 2;
// Message(what) to report a event that the state machine need to respond to
//
// Event indicates sevice records have been loaded
- public static final int SERVICE_RECORD_LOADED = 51;
+ static final int SERVICE_RECORD_LOADED = 51;
// Event indicates all the remote Bluetooth devices has been disconnected
- public static final int ALL_DEVICES_DISCONNECTED = 52;
+ static final int ALL_DEVICES_DISCONNECTED = 52;
// Event indicates the Bluetooth is connectable
- public static final int BECOME_PAIRABLE = 53;
+ static final int BECAME_PAIRABLE = 53;
// Event indicates the Bluetooth is non-connectable.
- public static final int BECOME_NON_PAIRABLE = 54;
+ static final int BECAME_NON_PAIRABLE = 54;
// Event indicates airplane mode is turned on
- public static final int AIRPLANE_MODE_ON = 55;
+ static final int AIRPLANE_MODE_ON = 55;
// Event indicates airplane mode is turned off
- public static final int AIRPLANE_MODE_OFF = 56;
+ static final int AIRPLANE_MODE_OFF = 56;
// private internal messages
//
@@ -95,8 +102,9 @@ final class BluetoothAdapterStateMachine extends StateMachine {
private static final int TURN_ON_CONTINUE = 102;
// Unload firmware, turning off Bluetooth module power
private static final int TURN_COLD = 103;
- // For NFC, turn on bluetooth for certain process
- private static final int TURN_ON_FOR_PRIVILEGED = 104;
+ // Per process enable / disable messages
+ static final int PER_PROCESS_TURN_ON = 104;
+ static final int PER_PROCESS_TURN_OFF = 105;
private Context mContext;
private BluetoothService mBluetoothService;
@@ -107,6 +115,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
private HotOff mHotOff;
private WarmUp mWarmUp;
private PowerOff mPowerOff;
+ private PerProcessState mPerProcessState;
// this is the BluetoothAdapter state that reported externally
private int mPublicState;
@@ -123,12 +132,15 @@ final class BluetoothAdapterStateMachine extends StateMachine {
mHotOff = new HotOff();
mWarmUp = new WarmUp();
mPowerOff = new PowerOff();
+ mPerProcessState = new PerProcessState();
addState(mBluetoothOn);
addState(mSwitching);
addState(mHotOff);
addState(mWarmUp);
addState(mPowerOff);
+ addState(mPerProcessState);
+
setInitialState(mPowerOff);
mPublicState = BluetoothAdapter.STATE_OFF;
@@ -142,12 +154,9 @@ final class BluetoothAdapterStateMachine extends StateMachine {
* Bluetooth module's power is off, firmware is not loaded.
*/
private class PowerOff extends State {
- private boolean mPersistSwitchOn = false;
-
@Override
public void enter() {
- if (DBG) log("Enter PowerOff: " + mPersistSwitchOn);
- mPersistSwitchOn = false;
+ if (DBG) log("Enter PowerOff: ");
}
@Override
public boolean processMessage(Message message) {
@@ -162,7 +171,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
if (prepareBluetooth()) {
// this is user request, save the setting
if ((Boolean) message.obj) {
- mPersistSwitchOn = true;
+ persistSwitchSetting(true);
}
// We will continue turn the BT on all the way to the BluetoothOn state
deferMessage(obtainMessage(TURN_ON_CONTINUE));
@@ -191,9 +200,21 @@ final class BluetoothAdapterStateMachine extends StateMachine {
transitionTo(mPowerOff);
broadcastState(BluetoothAdapter.STATE_OFF);
}
+ } else if (mContext.getResources().getBoolean
+ (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+ sendMessage(TURN_HOT);
}
break;
- case AIRPLANE_MODE_ON: // ignore
+ case PER_PROCESS_TURN_ON:
+ if (prepareBluetooth()) {
+ transitionTo(mWarmUp);
+ }
+ deferMessage(obtainMessage(PER_PROCESS_TURN_ON));
+ break;
+ case PER_PROCESS_TURN_OFF:
+ perProcessCallback(false, (IBluetoothStateChangeCallback) message.obj);
+ break;
+ case AIRPLANE_MODE_ON:
case USER_TURN_OFF: // ignore
break;
default:
@@ -276,6 +297,8 @@ final class BluetoothAdapterStateMachine extends StateMachine {
// on to the BluetoothOn state
case AIRPLANE_MODE_ON:
case AIRPLANE_MODE_OFF:
+ case PER_PROCESS_TURN_ON:
+ case PER_PROCESS_TURN_OFF:
deferMessage(message);
break;
case USER_TURN_OFF: // ignore
@@ -294,12 +317,9 @@ final class BluetoothAdapterStateMachine extends StateMachine {
* non-connectable.
*/
private class HotOff extends State {
- private boolean mPersistSwitchOn = false;
-
@Override
public void enter() {
- if (DBG) log("Enter HotOff: " + mPersistSwitchOn);
- mPersistSwitchOn = false;
+ if (DBG) log("Enter HotOff:");
}
@Override
@@ -310,9 +330,10 @@ final class BluetoothAdapterStateMachine extends StateMachine {
switch(message.what) {
case USER_TURN_ON:
if ((Boolean) message.obj) {
- mPersistSwitchOn = true;
+ persistSwitchSetting(true);
}
// let it fall to TURN_ON_CONTINUE:
+ //$FALL-THROUGH$
case TURN_ON_CONTINUE:
mBluetoothService.switchConnectable(true);
transitionTo(mSwitching);
@@ -328,13 +349,25 @@ final class BluetoothAdapterStateMachine extends StateMachine {
break;
case AIRPLANE_MODE_OFF:
if (getBluetoothPersistedSetting()) {
- mBluetoothService.switchConnectable(true);
transitionTo(mSwitching);
+ mBluetoothService.switchConnectable(true);
broadcastState(BluetoothAdapter.STATE_TURNING_ON);
}
break;
case USER_TURN_OFF: // ignore
break;
+ case PER_PROCESS_TURN_ON:
+ transitionTo(mPerProcessState);
+
+ // Resend the PER_PROCESS_TURN_ON message so that the callback
+ // can be sent through.
+ deferMessage(message);
+
+ mBluetoothService.switchConnectable(true);
+ break;
+ case PER_PROCESS_TURN_OFF:
+ perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
+ break;
default:
return NOT_HANDLED;
}
@@ -356,11 +389,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
boolean retValue = HANDLED;
switch(message.what) {
- case BECOME_PAIRABLE:
- if (mPowerOff.mPersistSwitchOn || mHotOff.mPersistSwitchOn) {
- persistSwitchSetting(true);
- mPowerOff.mPersistSwitchOn = mHotOff.mPersistSwitchOn = false;
- }
+ case BECAME_PAIRABLE:
String[] propVal = {"Pairable", mBluetoothService.getProperty("Pairable")};
mEventLoop.onPropertyChanged(propVal);
@@ -369,7 +398,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
transitionTo(mBluetoothOn);
broadcastState(BluetoothAdapter.STATE_ON);
break;
- case BECOME_NON_PAIRABLE:
+ case BECAME_NON_PAIRABLE:
if (mBluetoothService.getAdapterConnectionState() ==
BluetoothAdapter.STATE_DISCONNECTED) {
transitionTo(mHotOff);
@@ -385,9 +414,12 @@ final class BluetoothAdapterStateMachine extends StateMachine {
case USER_TURN_ON:
case AIRPLANE_MODE_OFF:
case AIRPLANE_MODE_ON:
+ case PER_PROCESS_TURN_ON:
+ case PER_PROCESS_TURN_OFF:
case USER_TURN_OFF:
deferMessage(message);
break;
+
default:
return NOT_HANDLED;
}
@@ -395,10 +427,6 @@ final class BluetoothAdapterStateMachine extends StateMachine {
}
private void finishSwitchingOff() {
- if (mBluetoothOn.mPersistBluetoothOff) {
- persistSwitchSetting(false);
- mBluetoothOn.mPersistBluetoothOff = false;
- }
mBluetoothService.finishDisable();
if (mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
@@ -415,7 +443,6 @@ final class BluetoothAdapterStateMachine extends StateMachine {
@Override
public void enter() {
if (DBG) log("Enter BluetoothOn: " + mPersistBluetoothOff);
- mPersistBluetoothOff = false;
}
@Override
public boolean processMessage(Message message) {
@@ -425,22 +452,40 @@ final class BluetoothAdapterStateMachine extends StateMachine {
switch(message.what) {
case USER_TURN_OFF:
if ((Boolean) message.obj) {
- mPersistBluetoothOff = true;
+ persistSwitchSetting(false);
+ }
+
+ if (mBluetoothService.isDiscovering()) {
+ mBluetoothService.cancelDiscovery();
+ }
+ if (!mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
+ transitionTo(mPerProcessState);
+ deferMessage(obtainMessage(USER_TURN_OFF));
+ break;
}
- // let it fall through to AIRPLANE_MODE_ON
+ //$FALL-THROUGH$ to AIRPLANE_MODE_ON
case AIRPLANE_MODE_ON:
transitionTo(mSwitching);
broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
mBluetoothService.switchConnectable(false);
mBluetoothService.disconnectDevices();
+
// we turn all the way to PowerOff with AIRPLANE_MODE_ON
if (message.what == AIRPLANE_MODE_ON) {
+ // We inform all the per process callbacks
+ allProcessesCallback(false);
deferMessage(obtainMessage(AIRPLANE_MODE_ON));
}
break;
case AIRPLANE_MODE_OFF: // ignore
case USER_TURN_ON: // ignore
break;
+ case PER_PROCESS_TURN_ON:
+ perProcessCallback(true, (IBluetoothStateChangeCallback)message.obj);
+ break;
+ case PER_PROCESS_TURN_OFF:
+ perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
+ break;
default:
return NOT_HANDLED;
}
@@ -449,6 +494,101 @@ final class BluetoothAdapterStateMachine extends StateMachine {
}
+
+ private class PerProcessState extends State {
+ IBluetoothStateChangeCallback mCallback = null;
+
+ @Override
+ public void enter() {
+ if (DBG) log("Enter PerProcessState");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log("PerProcessState process message: " + message.what);
+
+ boolean retValue = HANDLED;
+ switch (message.what) {
+ case PER_PROCESS_TURN_ON:
+ mCallback = (IBluetoothStateChangeCallback)getCurrentMessage().obj;
+
+ // If this is not the first application call the callback.
+ if (mBluetoothService.getNumberOfApplicationStateChangeTrackers() > 1) {
+ perProcessCallback(true, mCallback);
+ }
+ break;
+ case BECAME_PAIRABLE:
+ perProcessCallback(true, mCallback);
+ break;
+ case USER_TURN_ON:
+ broadcastState(BluetoothAdapter.STATE_TURNING_ON);
+ persistSwitchSetting(true);
+
+ String[] propVal = {"Pairable", mBluetoothService.getProperty("Pairable")};
+ mEventLoop.onPropertyChanged(propVal);
+
+ // run bluetooth now that it's turned on
+ mBluetoothService.runBluetooth();
+ transitionTo(mBluetoothOn);
+ broadcastState(BluetoothAdapter.STATE_ON);
+ break;
+ case USER_TURN_OFF:
+ broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
+ if (mBluetoothService.getAdapterConnectionState() !=
+ BluetoothAdapter.STATE_DISCONNECTED) {
+ mBluetoothService.disconnectDevices();
+ break;
+ }
+ //$FALL-THROUGH$ all devices are already disconnected
+ case ALL_DEVICES_DISCONNECTED:
+ mBluetoothService.finishDisable();
+ broadcastState(BluetoothAdapter.STATE_OFF);
+ break;
+ case PER_PROCESS_TURN_OFF:
+ perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
+ if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
+ mBluetoothService.switchConnectable(false);
+ }
+ break;
+ case BECAME_NON_PAIRABLE:
+ transitionTo(mHotOff);
+ if (!mContext.getResources().getBoolean
+ (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+ deferMessage(obtainMessage(TURN_COLD));
+ }
+ break;
+ case AIRPLANE_MODE_ON:
+ mBluetoothService.switchConnectable(false);
+ allProcessesCallback(false);
+ // we turn all the way to PowerOff with AIRPLANE_MODE_ON
+ deferMessage(obtainMessage(AIRPLANE_MODE_ON));
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return retValue;
+ }
+ }
+
+
+ private void perProcessCallback(boolean on, IBluetoothStateChangeCallback c) {
+ if (c == null) return;
+
+ try {
+ c.onBluetoothStateChange(on);
+ } catch (RemoteException e) {}
+ }
+
+ private void allProcessesCallback(boolean on) {
+ for (IBluetoothStateChangeCallback c:
+ mBluetoothService.getApplicationStateChangeCallbacks()) {
+ perProcessCallback(on, c);
+ }
+ if (!on) {
+ mBluetoothService.clearApplicationStateChangeTracker();
+ }
+ }
+
/**
* Return the public BluetoothAdapter state
*/
@@ -476,7 +616,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
private void broadcastState(int newState) {
- if (DBG) log("Bluetooth state " + mPublicState + " -> " + newState);
+ log("Bluetooth state " + mPublicState + " -> " + newState);
if (mPublicState == newState) {
return;
}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 107a2a9..2cab05c 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -340,9 +340,9 @@ class BluetoothEventLoop {
if (name.equals("Pairable")) {
if (pairable.equals("true")) {
- mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECOME_PAIRABLE);
+ mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECAME_PAIRABLE);
} else {
- mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECOME_NON_PAIRABLE);
+ mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECAME_NON_PAIRABLE);
}
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 34f1971..9e66957 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -39,6 +39,7 @@ import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothHealthCallback;
+import android.bluetooth.IBluetoothStateChangeCallback;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -68,13 +69,15 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
-import java.io.InputStreamReader;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -101,6 +104,8 @@ public class BluetoothService extends IBluetooth.Stub {
private final BluetoothBondState mBondState; // local cache of bondings
private final IBatteryStats mBatteryStats;
private final Context mContext;
+ private Map<Integer, IBluetoothStateChangeCallback> mStateChangeTracker =
+ Collections.synchronizedMap(new HashMap<Integer, IBluetoothStateChangeCallback>());
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
@@ -114,6 +119,9 @@ public class BluetoothService extends IBluetooth.Stub {
private static final int MESSAGE_UUID_INTENT = 1;
private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 2;
+ private static final int RFCOMM_RECORD_REAPER = 10;
+ private static final int STATE_CHANGE_REAPER = 11;
+
// The time (in millisecs) to delay the pairing attempt after the first
// auto pairing attempt fails. We use an exponential delay with
// INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
@@ -1466,7 +1474,7 @@ public class BluetoothService extends IBluetooth.Stub {
int pid = Binder.getCallingPid();
mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
try {
- b.linkToDeath(new Reaper(handle, pid), 0);
+ b.linkToDeath(new Reaper(handle, pid, RFCOMM_RECORD_REAPER), 0);
} catch (RemoteException e) {}
return handle;
}
@@ -1489,20 +1497,85 @@ public class BluetoothService extends IBluetooth.Stub {
}
private class Reaper implements IBinder.DeathRecipient {
- int pid;
- int handle;
- Reaper(int handle, int pid) {
- this.pid = pid;
- this.handle = handle;
+ int mPid;
+ int mHandle;
+ int mType;
+
+ Reaper(int handle, int pid, int type) {
+ mPid = pid;
+ mHandle = handle;
+ mType = type;
+ }
+
+ Reaper(int pid, int type) {
+ mPid = pid;
+ mType = type;
}
+
+ @Override
public void binderDied() {
synchronized (BluetoothService.this) {
- if (DBG) Log.d(TAG, "Tracked app " + pid + " died");
- checkAndRemoveRecord(handle, pid);
+ if (DBG) Log.d(TAG, "Tracked app " + mPid + " died" + "Type:" + mType);
+ if (mType == RFCOMM_RECORD_REAPER) {
+ checkAndRemoveRecord(mHandle, mPid);
+ } else if (mType == STATE_CHANGE_REAPER) {
+ mStateChangeTracker.remove(mPid);
+ }
}
}
}
+
+ @Override
+ public boolean changeApplicationBluetoothState(boolean on,
+ IBluetoothStateChangeCallback callback, IBinder binder) {
+ int pid = Binder.getCallingPid();
+ //mStateChangeTracker is a synchronized map
+ if (!mStateChangeTracker.containsKey(pid)) {
+ if (on) {
+ mStateChangeTracker.put(pid, callback);
+ } else {
+ return false;
+ }
+ } else if (!on) {
+ mStateChangeTracker.remove(pid);
+ }
+
+ if (binder != null) {
+ try {
+ binder.linkToDeath(new Reaper(pid, STATE_CHANGE_REAPER), 0);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ int type;
+ if (on) {
+ type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_ON;
+ } else {
+ type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_OFF;
+ }
+
+ mBluetoothState.sendMessage(type, callback);
+ return true;
+ }
+
+ boolean isApplicationStateChangeTrackerEmpty() {
+ return mStateChangeTracker.isEmpty();
+ }
+
+ void clearApplicationStateChangeTracker() {
+ mStateChangeTracker.clear();
+ }
+
+ Collection<IBluetoothStateChangeCallback> getApplicationStateChangeCallbacks() {
+ return mStateChangeTracker.values();
+ }
+
+ int getNumberOfApplicationStateChangeTrackers() {
+ return mStateChangeTracker.size();
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 1926c92..b4e8ab4 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -227,7 +227,7 @@ public abstract class TextToSpeechService extends Service {
private boolean mFirstIdle = true;
public SynthThread() {
- super(SYNTH_THREAD_NAME, android.os.Process.THREAD_PRIORITY_AUDIO);
+ super(SYNTH_THREAD_NAME, android.os.Process.THREAD_PRIORITY_DEFAULT);
}
@Override
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5ab2024..d9efe0c 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -25,16 +25,18 @@ import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Slog;
+/**
+ * Provides information about the display size and density.
+ */
public class Display {
static final String TAG = "Display";
static final boolean DEBUG_COMPAT = false;
/**
- * Specify the default Display
+ * The default Display id.
*/
public static final int DEFAULT_DISPLAY = 0;
-
/**
* Use {@link android.view.WindowManager#getDefaultDisplay()
* WindowManager.getDefaultDisplay()} to create a Display object.
@@ -55,16 +57,6 @@ public class Display {
init(display);
}
- /** @hide */
- public static void setCompatibilityInfo(CompatibilityInfo compatInfo) {
- if (compatInfo != null && (compatInfo.isScalingRequired()
- || !compatInfo.supportsScreen())) {
- sCompatibilityInfo = compatInfo;
- } else {
- sCompatibilityInfo = null;
- }
- }
-
/**
* Returns the index of this display. This is currently undefined; do
* not use.
@@ -80,25 +72,29 @@ public class Display {
native static int getDisplayCount();
/**
- * Returns the raw size of the display, in pixels. Note that this
- * should <em>not</em> generally be used for computing layouts, since
- * a device will typically have screen decoration (such as a status bar)
+ * Gets the size of the display, in pixels.
+ * <p>
+ * Note that this value should <em>not</em> be used for computing layouts,
+ * since a device will typically have screen decoration (such as a status bar)
* along the edges of the display that reduce the amount of application
- * space available from the raw size returned here. This value is
- * adjusted for you based on the current rotation of the display.
+ * space available from the size returned here. Layouts should instead use
+ * the window size.
+ * </p><p>
+ * The size is adjusted based on the current rotation of the display.
+ * </p><p>
+ * The size returned by this method does not necessarily represent the
+ * actual raw size (native resolution) of the display. The returned size may
+ * be adjusted to exclude certain system decor elements that are always visible.
+ * It may also be scaled to provide compatibility with older applications that
+ * were originally designed for smaller displays.
+ * </p>
+ *
+ * @param outSize A {@link Point} object to receive the size information.
*/
public void getSize(Point outSize) {
getSizeInternal(outSize, true);
}
- /**
- * Returns the raw size of the display, in pixels. Note that this
- * should <em>not</em> generally be used for computing layouts, since
- * a device will typically have screen decoration (such as a status bar)
- * along the edges of the display that reduce the amount of application
- * space available from the raw size returned here. This value is
- * adjusted for you based on the current rotation of the display.
- */
private void getSizeInternal(Point outSize, boolean doCompat) {
try {
IWindowManager wm = getWindowManager();
@@ -118,8 +114,8 @@ public class Display {
} else {
// This is just for boot-strapping, initializing the
// system process before the window manager is up.
- outSize.x = getRealWidth();
- outSize.y = getRealHeight();
+ outSize.x = getRawWidth();
+ outSize.y = getRawHeight();
}
if (DEBUG_COMPAT && doCompat) Slog.v(TAG, "Returning display size: " + outSize);
} catch (RemoteException e) {
@@ -128,7 +124,10 @@ public class Display {
}
/**
- * This is just easier for some parts of the framework.
+ * Gets the size of the display as a rectangle, in pixels.
+ *
+ * @param outSize A {@link Rect} object to receive the size information.
+ * @see #getSize(Point)
*/
public void getRectSize(Rect outSize) {
synchronized (mTmpPoint) {
@@ -182,14 +181,49 @@ public class Display {
}
}
- /** @hide Returns the actual screen size, not including any decor. */
- native public int getRealWidth();
- /** @hide Returns the actual screen size, not including any decor. */
- native public int getRealHeight();
+ /**
+ * Gets the real size of the display without subtracting any window decor or
+ * applying any compatibility scale factors.
+ * <p>
+ * The real size may be smaller than the raw size when the window manager
+ * is emulating a smaller display (using adb shell am display-size).
+ * </p><p>
+ * The size is adjusted based on the current rotation of the display.
+ * </p>
+ * @hide
+ */
+ public void getRealSize(Point outSize) {
+ try {
+ IWindowManager wm = getWindowManager();
+ if (wm != null) {
+ wm.getRealDisplaySize(outSize);
+ } else {
+ // This is just for boot-strapping, initializing the
+ // system process before the window manager is up.
+ outSize.x = getRawWidth();
+ outSize.y = getRawHeight();
+ }
+ } catch (RemoteException e) {
+ Slog.w("Display", "Unable to get real display size", e);
+ }
+ }
- /** @hide special for when we are faking the screen size. */
+ /**
+ * Gets the raw width of the display, in pixels.
+ * <p>
+ * The size is adjusted based on the current rotation of the display.
+ * </p>
+ * @hide
+ */
native public int getRawWidth();
- /** @hide special for when we are faking the screen size. */
+
+ /**
+ * Gets the raw height of the display, in pixels.
+ * <p>
+ * The size is adjusted based on the current rotation of the display.
+ * </p>
+ * @hide
+ */
native public int getRawHeight();
/**
@@ -235,17 +269,24 @@ public class Display {
}
/**
- * Initialize a DisplayMetrics object from this display's data.
- *
- * @param outMetrics
+ * Gets display metrics that describe the size and density of this display.
+ * <p>
+ * The size is adjusted based on the current rotation of the display.
+ * </p><p>
+ * The size returned by this method does not necessarily represent the
+ * actual raw size (native resolution) of the display. The returned size may
+ * be adjusted to exclude certain system decor elements that are always visible.
+ * It may also be scaled to provide compatibility with older applications that
+ * were originally designed for smaller displays.
+ * </p>
+ *
+ * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
*/
public void getMetrics(DisplayMetrics outMetrics) {
synchronized (mTmpPoint) {
getSizeInternal(mTmpPoint, false);
- outMetrics.widthPixels = mTmpPoint.x;
- outMetrics.heightPixels = mTmpPoint.y;
+ getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y);
}
- getNonSizeMetrics(outMetrics);
CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
if (ci != null) {
@@ -257,22 +298,44 @@ public class Display {
}
/**
- * Initialize a DisplayMetrics object from this display's data.
- *
- * @param outMetrics
+ * Gets display metrics based on the real size of this display.
* @hide
*/
public void getRealMetrics(DisplayMetrics outMetrics) {
- outMetrics.widthPixels = getRealWidth();
- outMetrics.heightPixels = getRealHeight();
- getNonSizeMetrics(outMetrics);
+ synchronized (mTmpPoint) {
+ getRealSize(mTmpPoint);
+ getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y);
+ }
+ }
+
+ /**
+ * If the display is mirrored to an external HDMI display, returns the
+ * width of that display.
+ * @hide
+ */
+ public int getRawExternalWidth() {
+ return 1280;
+ }
+
+ /**
+ * If the display is mirrored to an external HDMI display, returns the
+ * height of that display.
+ * @hide
+ */
+ public int getRawExternalHeight() {
+ return 720;
}
- private void getNonSizeMetrics(DisplayMetrics outMetrics) {
+ /**
+ * Gets display metrics based on an explicit assumed display size.
+ * @hide
+ */
+ public void getMetricsWithSize(DisplayMetrics outMetrics,
+ int width, int height) {
outMetrics.densityDpi = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f);
- outMetrics.noncompatWidthPixels = outMetrics.widthPixels;
- outMetrics.noncompatHeightPixels = outMetrics.heightPixels;
+ outMetrics.noncompatWidthPixels = outMetrics.widthPixels = width;
+ outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
outMetrics.density = outMetrics.noncompatDensity = mDensity;
outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
@@ -315,8 +378,6 @@ public class Display {
private static boolean sInitialized = false;
private static IWindowManager sWindowManager;
- private static volatile CompatibilityInfo sCompatibilityInfo;
-
/**
* Returns a display object which uses the metric's width/height instead.
* @hide
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index d22fa6e..ac0abc3 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -51,7 +51,7 @@ class GLES20Canvas extends HardwareCanvas {
// The native renderer will be destroyed when this object dies.
// DO NOT overwrite this reference once it is set.
- @SuppressWarnings("unused")
+ @SuppressWarnings({"unused", "FieldCanBeLocal"})
private CanvasFinalizer mFinalizer;
private int mWidth;
@@ -277,14 +277,25 @@ class GLES20Canvas extends HardwareCanvas {
///////////////////////////////////////////////////////////////////////////
/**
+ * Must match Caches::FlushMode values
+ *
* @see #flushCaches(int)
*/
- public static final int FLUSH_CACHES_MODERATE = 0;
+ public static final int FLUSH_CACHES_LAYERS = 0;
+
+ /**
+ * Must match Caches::FlushMode values
+ *
+ * @see #flushCaches(int)
+ */
+ public static final int FLUSH_CACHES_MODERATE = 1;
/**
+ * Must match Caches::FlushMode values
+ *
* @see #flushCaches(int)
*/
- public static final int FLUSH_CACHES_FULL = 1;
+ public static final int FLUSH_CACHES_FULL = 2;
/**
* Flush caches to reclaim as much memory as possible. The amount of memory
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 078222b..c987f48 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -38,7 +38,7 @@ import android.util.Pools;
class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> {
// The recording canvas pool should be large enough to handle a deeply nested
// view hierarchy because display lists are generated recursively.
- private static final int POOL_LIMIT = 50;
+ private static final int POOL_LIMIT = 25;
private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool(
Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() {
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
index 7adac1c..41f16e2 100644
--- a/core/java/android/view/GLES20RenderLayer.java
+++ b/core/java/android/view/GLES20RenderLayer.java
@@ -24,7 +24,6 @@ import android.graphics.Canvas;
* {@link Canvas} that can be used to render into an FBO using OpenGL.
*/
class GLES20RenderLayer extends GLES20Layer {
-
private int mLayerWidth;
private int mLayerHeight;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 14a77b4..5404e3a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -140,6 +140,13 @@ public abstract class HardwareRenderer {
abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException;
/**
+ * Destoys the layers used by the specified view hierarchy.
+ *
+ * @param view The root of the view hierarchy
+ */
+ abstract void destroyLayers(View view);
+
+ /**
* This method should be invoked whenever the current hardware renderer
* context should be reset.
*/
@@ -283,7 +290,7 @@ public abstract class HardwareRenderer {
* see {@link android.content.ComponentCallbacks}
*/
static void trimMemory(int level) {
- Gl20Renderer.flushCaches(level);
+ Gl20Renderer.trimMemory(level);
}
/**
@@ -622,18 +629,8 @@ public abstract class HardwareRenderer {
+ "from multiple threads");
}
- /*
- * The window size has changed, so we need to create a new
- * surface.
- */
- if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
- /*
- * Unbind and destroy the old EGL surface, if
- * there is one.
- */
- sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
- }
+ // In case we need to destroy an existing surface
+ destroySurface();
// Create an EGL surface we can render into.
mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
@@ -677,22 +674,13 @@ public abstract class HardwareRenderer {
}
EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
- int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
+ int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
- mGlVersion != 0 ? attrib_list : null);
+ mGlVersion != 0 ? attribs : null);
}
@Override
- void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
- SurfaceHolder holder) throws Surface.OutOfResourcesException {
- if (isRequested()) {
- checkEglErrors();
- super.initializeIfNeeded(width, height, attachInfo, holder);
- }
- }
-
- @Override
void destroy(boolean full) {
if (full && mCanvas != null) {
mCanvas = null;
@@ -702,15 +690,21 @@ public abstract class HardwareRenderer {
mDestroyed = true;
- sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+ destroySurface();
- mEglSurface = null;
mGl = null;
setEnabled(false);
}
+ void destroySurface() {
+ if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+ mEglSurface = null;
+ }
+ }
+
@Override
void invalidate() {
// Cancels any existing buffer to ensure we'll get a buffer
@@ -726,6 +720,7 @@ public abstract class HardwareRenderer {
@Override
void setup(int width, int height) {
+ checkCurrent();
mCanvas.setViewport(width, height);
}
@@ -819,7 +814,7 @@ public abstract class HardwareRenderer {
* {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
* {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
*/
- private int checkCurrent() {
+ int checkCurrent() {
if (mEglThread != Thread.currentThread()) {
throw new IllegalStateException("Hardware acceleration can only be used with a " +
"single UI thread.\nOriginal thread: " + mEglThread + "\n" +
@@ -847,6 +842,9 @@ public abstract class HardwareRenderer {
static class Gl20Renderer extends GlRenderer {
private GLES20Canvas mGlCanvas;
+ private static EGLSurface sPbuffer;
+ private static final Object[] sPbufferLock = new Object[0];
+
Gl20Renderer(boolean translucent) {
super(2, translucent);
}
@@ -926,14 +924,54 @@ public abstract class HardwareRenderer {
return ((GLES20TextureLayer) layer).getSurfaceTexture();
}
+ @Override
+ void destroyLayers(View view) {
+ if (view != null && isEnabled()) {
+ checkCurrent();
+ destroyHardwareLayer(view);
+ GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+ }
+ }
+
+ private void destroyHardwareLayer(View view) {
+ view.destroyLayer();
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+
+ int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ destroyHardwareLayer(group.getChildAt(i));
+ }
+ }
+ }
+
static HardwareRenderer create(boolean translucent) {
if (GLES20Canvas.isAvailable()) {
return new Gl20Renderer(translucent);
}
return null;
}
-
- static void flushCaches(int level) {
+
+ static void trimMemory(int level) {
+ if (sEgl == null || sEglConfig == null) return;
+
+ EGLContext eglContext = sEglContextStorage.get();
+ // We do not have OpenGL objects
+ if (eglContext == null) {
+ return;
+ } else {
+ synchronized (sPbufferLock) {
+ // Create a temporary 1x1 pbuffer so we have a context
+ // to clear our OpenGL objects
+ if (sPbuffer == null) {
+ sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
+ EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
+ });
+ }
+ }
+ sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+ }
+
switch (level) {
case ComponentCallbacks.TRIM_MEMORY_MODERATE:
GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index ad17edf..81cd798 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -55,6 +55,7 @@ interface IWindowManager
boolean inputMethodClientHasFocus(IInputMethodClient client);
void getDisplaySize(out Point size);
+ void getRealDisplaySize(out Point size);
int getMaximumSizeDimension();
void setForcedDisplaySize(int longDimen, int shortDimen);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 88f59d4..da5c7b2 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1123,7 +1123,10 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
/**
- * Button constant: Primary button (left mouse button, stylus tip).
+ * Button constant: Primary button (left mouse button).
+ *
+ * This button constant is not set in response to simple touches with a finger
+ * or stylus tip. The user must actually push a button.
*
* @see #getButtonState
*/
@@ -1215,55 +1218,32 @@ public final class MotionEvent extends InputEvent implements Parcelable {
public static final int TOOL_TYPE_UNKNOWN = 0;
/**
- * Tool type constant: The tool is a finger directly touching the display.
- *
- * This is a <em>direct</em> positioning tool.
+ * Tool type constant: The tool is a finger.
*
* @see #getToolType
*/
public static final int TOOL_TYPE_FINGER = 1;
/**
- * Tool type constant: The tool is a stylus directly touching the display
- * or hovering slightly above it.
- *
- * This is a <em>direct</em> positioning tool.
+ * Tool type constant: The tool is a stylus.
*
* @see #getToolType
*/
public static final int TOOL_TYPE_STYLUS = 2;
/**
- * Tool type constant: The tool is a mouse or trackpad that translates
- * relative motions into cursor movements on the display.
- *
- * This is an <em>indirect</em> positioning tool.
+ * Tool type constant: The tool is a mouse or trackpad.
*
* @see #getToolType
*/
public static final int TOOL_TYPE_MOUSE = 3;
/**
- * Tool type constant: The tool is a finger on a touch pad that is not
- * directly attached to the display. Finger movements on the touch pad
- * may be translated into touches on the display, possibly with visual feedback.
- *
- * This is an <em>indirect</em> positioning tool.
- *
- * @see #getToolType
- */
- public static final int TOOL_TYPE_INDIRECT_FINGER = 4;
-
- /**
- * Tool type constant: The tool is a stylus on a digitizer tablet that is not
- * attached to the display. Stylus movements on the digitizer may be translated
- * into touches on the display, possibly with visual feedback.
- *
- * This is an <em>indirect</em> positioning tool.
+ * Tool type constant: The tool is an eraser or a stylus being used in an inverted posture.
*
* @see #getToolType
*/
- public static final int TOOL_TYPE_INDIRECT_STYLUS = 5;
+ public static final int TOOL_TYPE_ERASER = 4;
// NOTE: If you add a new tool type here you must also add it to:
// native/include/android/input.h
@@ -1276,8 +1256,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
names.append(TOOL_TYPE_FINGER, "TOOL_TYPE_FINGER");
names.append(TOOL_TYPE_STYLUS, "TOOL_TYPE_STYLUS");
names.append(TOOL_TYPE_MOUSE, "TOOL_TYPE_MOUSE");
- names.append(TOOL_TYPE_INDIRECT_FINGER, "TOOL_TYPE_INDIRECT_FINGER");
- names.append(TOOL_TYPE_INDIRECT_STYLUS, "TOOL_TYPE_INDIRECT_STYLUS");
+ names.append(TOOL_TYPE_ERASER, "TOOL_TYPE_ERASER");
}
// Private value for history pos that obtains the current sample.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2213188..5dcb84f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -672,19 +672,23 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
private static final int FITS_SYSTEM_WINDOWS = 0x00000002;
/**
- * This view is visible. Use with {@link #setVisibility(int)}.
+ * This view is visible.
+ * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
+ * android:visibility}.
*/
public static final int VISIBLE = 0x00000000;
/**
* This view is invisible, but it still takes up space for layout purposes.
- * Use with {@link #setVisibility(int)}.
+ * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
+ * android:visibility}.
*/
public static final int INVISIBLE = 0x00000004;
/**
* This view is invisible, and it doesn't take any space for layout
- * purposes. Use with {@link #setVisibility(int)}.
+ * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
+ * android:visibility}.
*/
public static final int GONE = 0x00000008;
@@ -9226,10 +9230,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
destroyDrawingCache();
- if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
- }
+ destroyLayer();
if (mDisplayList != null) {
mDisplayList.invalidate();
@@ -9601,21 +9602,10 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
// Destroy any previous software drawing cache if needed
switch (mLayerType) {
case LAYER_TYPE_HARDWARE:
- if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
- }
+ destroyLayer();
// fall through - unaccelerated views may use software layer mechanism instead
case LAYER_TYPE_SOFTWARE:
- if (mDrawingCache != null) {
- mDrawingCache.recycle();
- mDrawingCache = null;
- }
-
- if (mUnscaledDrawingCache != null) {
- mUnscaledDrawingCache.recycle();
- mUnscaledDrawingCache = null;
- }
+ destroyDrawingCache();
break;
default:
break;
@@ -9741,6 +9731,13 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
return mHardwareLayer;
}
+ void destroyLayer() {
+ if (mHardwareLayer != null) {
+ mHardwareLayer.destroy();
+ mHardwareLayer = null;
+ }
+ }
+
/**
* <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call
* to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 8cf03a6..697636e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -788,7 +788,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final View[] children = mChildren;
for (int i = 0; i < childrenCount; i++) {
View child = children[i];
- if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+ if ((child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
child.findViewsWithText(outViews, text);
}
}
@@ -2162,6 +2162,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
+ if ((mPrivateFlags & IS_ROOT_NAMESPACE) != 0) {
+ return;
+ }
for (int i = 0, count = mChildrenCount; i < count; i++) {
View child = mChildren[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 470493d..76e16a9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -235,6 +235,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
final Configuration mLastConfiguration = new Configuration();
final Configuration mPendingConfiguration = new Configuration();
+
class ResizedInfo {
Rect coveredInsets;
Rect visibleInsets;
@@ -540,6 +541,13 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
}
+ private void destroyHardwareResources() {
+ if (mAttachInfo.mHardwareRenderer.isEnabled()) {
+ mAttachInfo.mHardwareRenderer.destroyLayers(mView);
+ }
+ mAttachInfo.mHardwareRenderer.destroy(false);
+ }
+
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
@@ -824,8 +832,10 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
// NOTE -- system code, won't try to do compat mode.
Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
- desiredWindowWidth = disp.getRealWidth();
- desiredWindowHeight = disp.getRealHeight();
+ Point size = new Point();
+ disp.getRealSize(size);
+ desiredWindowWidth = size.x;
+ desiredWindowHeight = size.y;
} else {
DisplayMetrics packageMetrics =
mView.getContext().getResources().getDisplayMetrics();
@@ -869,7 +879,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
host.dispatchWindowVisibilityChanged(viewVisibility);
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
if (mAttachInfo.mHardwareRenderer != null) {
- mAttachInfo.mHardwareRenderer.destroy(false);
+ destroyHardwareResources();
}
}
if (viewVisibility == View.GONE) {
@@ -979,8 +989,10 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
// NOTE -- system code, won't try to do compat mode.
Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
- desiredWindowWidth = disp.getRealWidth();
- desiredWindowHeight = disp.getRealHeight();
+ Point size = new Point();
+ disp.getRealSize(size);
+ desiredWindowWidth = size.x;
+ desiredWindowHeight = size.y;
} else {
DisplayMetrics packageMetrics = res.getDisplayMetrics();
desiredWindowWidth = packageMetrics.widthPixels;
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
index 3cb5e24..a21d3ee 100644
--- a/core/java/android/webkit/DebugFlags.java
+++ b/core/java/android/webkit/DebugFlags.java
@@ -47,7 +47,7 @@ class DebugFlags {
public static final boolean WEB_VIEW_CORE = false;
/*
* Set to true to allow the WebTextView to draw on top of the web page in a
- * different color so that you can see how the two line up.
+ * different color with no background so you can see how the two line up.
*/
public static final boolean DRAW_WEBTEXTVIEW = false;
}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index d54230c..b8c4e22 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -25,7 +25,7 @@ import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -87,7 +87,6 @@ import junit.framework.Assert;
// Keep track of the text before the change so we know whether we actually
// need to send down the DOM events.
private String mPreChange;
- private Drawable mBackground;
// Variables for keeping track of the touch down, to send to the WebView
// when a drag starts
private float mDragStartX;
@@ -190,6 +189,8 @@ import junit.framework.Assert;
// that other applications that use embedded WebViews will properly
// display the text in password textfields.
setTextColor(DebugFlags.DRAW_WEBTEXTVIEW ? Color.RED : Color.BLACK);
+ setBackgroundDrawable(DebugFlags.DRAW_WEBTEXTVIEW ? null : new ColorDrawable(Color.WHITE));
+
// This helps to align the text better with the text in the web page.
setIncludeFontPadding(false);
@@ -423,24 +424,6 @@ import junit.framework.Assert;
// makeNewLayout does.
super.makeNewLayout(w, hintWidth, boring, hintBoring, ellipsisWidth,
bringIntoView);
-
- // For fields that do not draw, create a layout which is altered so that
- // the text lines up.
- if (DebugFlags.DRAW_WEBTEXTVIEW || willNotDraw()) {
- float lineHeight = -1;
- if (mWebView != null) {
- float height = mWebView.nativeFocusCandidateLineHeight();
- if (height != -1) {
- lineHeight = height * mWebView.getScale();
- }
- }
- CharSequence text = getText();
- // Copy from the existing Layout.
- mLayout = new WebTextViewLayout(text, text, getPaint(), mLayout.getWidth(),
- mLayout.getAlignment(), mLayout.getSpacingMultiplier(),
- mLayout.getSpacingAdd(), false, null, ellipsisWidth,
- lineHeight);
- }
lineUpScroll();
}
@@ -491,51 +474,6 @@ import junit.framework.Assert;
return connection;
}
- /**
- * In general, TextView makes a call to InputMethodManager.updateSelection
- * in onDraw. However, in the general case of WebTextView, we do not draw.
- * This method is called by WebView.onDraw to take care of the part that
- * needs to be called.
- */
- /* package */ void onDrawSubstitute() {
- if (!willNotDraw()) {
- // If the WebTextView is set to draw, such as in the case of a
- // password, onDraw calls updateSelection(), so this code path is
- // unnecessary.
- return;
- }
- // This code is copied from TextView.onDraw(). That code does not get
- // executed, however, because the WebTextView does not draw, allowing
- // webkit's drawing to show through.
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null && imm.isActive(this)) {
- Spannable sp = (Spannable) getText();
- int selStart = Selection.getSelectionStart(sp);
- int selEnd = Selection.getSelectionEnd(sp);
- int candStart = EditableInputConnection.getComposingSpanStart(sp);
- int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
- imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- // onDraw should only be called for password fields. If WebTextView is
- // still drawing, but is no longer corresponding to a password field,
- // remove it.
- if (!DebugFlags.DRAW_WEBTEXTVIEW && (mWebView == null
- || !mWebView.nativeFocusCandidateIsPassword()
- || !isSameTextField(mWebView.nativeFocusCandidatePointer()))) {
- // Although calling remove() would seem to make more sense here,
- // changing it to not be a password field will make it not draw.
- // Other code will make sure that it is removed completely, but this
- // way the user will not see it.
- setInPassword(false);
- } else {
- super.onDraw(canvas);
- }
- }
-
@Override
public void onEditorAction(int actionCode) {
switch (actionCode) {
@@ -928,102 +866,6 @@ import junit.framework.Assert;
if (mWebView != null) mWebView.incrementTextGeneration();
}
- /**
- * Determine whether to use the system-wide password disguising method,
- * or to use none.
- * @param inPassword True if the textfield is a password field.
- */
- /* package */ void setInPassword(boolean inPassword) {
- if (inPassword) {
- setInputType(InputType.TYPE_CLASS_TEXT | EditorInfo.
- TYPE_TEXT_VARIATION_WEB_PASSWORD);
- createBackground();
- }
- // For password fields, draw the WebTextView. For others, just show
- // webkit's drawing.
- if (!DebugFlags.DRAW_WEBTEXTVIEW) {
- setWillNotDraw(!inPassword);
- }
- setBackgroundDrawable(inPassword ? mBackground : null);
- }
-
- /**
- * Private class used for the background of a password textfield.
- */
- private static class OutlineDrawable extends Drawable {
- private Paint mBackgroundPaint;
- private Paint mOutlinePaint;
- private float[] mLines;
- public OutlineDrawable() {
- mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBackgroundPaint.setColor(Color.WHITE);
-
- mOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mOutlinePaint.setColor(Color.BLACK);
- mOutlinePaint.setStyle(Paint.Style.STROKE);
-
- mLines = new float[16];
- }
- @Override
- public void setBounds(int left, int top, int right, int bottom) {
- super.setBounds(left, top, right, bottom);
- bottom--;
- right -= 2;
- // Top line
- mLines[0] = left;
- mLines[1] = top + 1;
- mLines[2] = right;
- mLines[3] = top + 1;
- // Right line
- mLines[4] = right;
- mLines[5] = top;
- mLines[6] = right;
- mLines[7] = bottom;
- // Bottom line
- mLines[8] = left;
- mLines[9] = bottom;
- mLines[10] = right;
- mLines[11] = bottom;
- // Left line
- mLines[12] = left + 1;
- mLines[13] = top;
- mLines[14] = left + 1;
- mLines[15] = bottom;
- }
- @Override
- public void draw(Canvas canvas) {
- // Draw the background.
- canvas.drawRect(getBounds(), mBackgroundPaint);
- // Draw the outline.
- canvas.drawLines(mLines, mOutlinePaint);
- }
- // Always want it to be opaque.
- @Override
- public int getOpacity() {
- return PixelFormat.OPAQUE;
- }
- // These are needed because they are abstract in Drawable.
- @Override
- public void setAlpha(int alpha) { }
- @Override
- public void setColorFilter(ColorFilter cf) { }
- }
-
- /**
- * Create a background for the WebTextView and set up the paint for drawing
- * the text. This way, we can see the password transformation of the
- * system, which (optionally) shows the actual text before changing to dots.
- * The background is necessary to hide the webkit-drawn text beneath.
- */
- private void createBackground() {
- if (mBackground != null) {
- return;
- }
- mBackground = new OutlineDrawable();
-
- setGravity(Gravity.CENTER_VERTICAL);
- }
-
@Override
public void setInputType(int type) {
mFromSetInputType = true;
@@ -1072,7 +914,8 @@ import junit.framework.Assert;
lp.height = height;
}
if (getParent() == null) {
- mWebView.addView(this, lp);
+ // Insert the view so that it's drawn first (at index 0)
+ mWebView.addView(this, 0, lp);
} else {
setLayoutParams(lp);
}
@@ -1145,7 +988,6 @@ import junit.framework.Assert;
/* package */ void setType(int type) {
if (mWebView == null) return;
boolean single = true;
- boolean inPassword = false;
int maxLength = -1;
int inputType = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
@@ -1167,7 +1009,7 @@ import junit.framework.Assert;
imeOptions |= EditorInfo.IME_ACTION_NONE;
break;
case PASSWORD:
- inPassword = true;
+ inputType |= EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD;
imeOptions |= EditorInfo.IME_ACTION_GO;
break;
case SEARCH:
@@ -1219,7 +1061,7 @@ import junit.framework.Assert;
setHorizontallyScrolling(single);
setInputType(inputType);
setImeOptions(imeOptions);
- setInPassword(inPassword);
+ setVisibility(VISIBLE);
AutoCompleteAdapter adapter = null;
setAdapterCustom(adapter);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index e24ab58..a935a67 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4068,9 +4068,6 @@ public class WebView extends AbsoluteLayout
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
- if (inEditingMode()) {
- mWebTextView.onDrawSubstitute();
- }
mWebViewCore.signalRepaintDone();
if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas)) {
@@ -4287,18 +4284,18 @@ public class WebView extends AbsoluteLayout
private void onZoomAnimationStart() {
// If it is in password mode, turn it off so it does not draw misplaced.
- if (inEditingMode() && nativeFocusCandidateIsPassword()) {
- mWebTextView.setInPassword(false);
+ if (inEditingMode()) {
+ mWebTextView.setVisibility(INVISIBLE);
}
}
private void onZoomAnimationEnd() {
// adjust the edit text view if needed
- if (inEditingMode() && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)
- && nativeFocusCandidateIsPassword()) {
+ if (inEditingMode()
+ && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)) {
// If it is a password field, start drawing the WebTextView once
// again.
- mWebTextView.setInPassword(true);
+ mWebTextView.setVisibility(VISIBLE);
}
}
@@ -4593,37 +4590,23 @@ public class WebView extends AbsoluteLayout
}
String text = nativeFocusCandidateText();
int nodePointer = nativeFocusCandidatePointer();
- if (alreadyThere && mWebTextView.isSameTextField(nodePointer)) {
- // It is possible that we have the same textfield, but it has moved,
- // i.e. In the case of opening/closing the screen.
- // In that case, we need to set the dimensions, but not the other
- // aspects.
- // If the text has been changed by webkit, update it. However, if
- // there has been more UI text input, ignore it. We will receive
- // another update when that text is recognized.
- if (text != null && !text.equals(mWebTextView.getText().toString())
- && nativeTextGeneration() == mTextGeneration) {
- mWebTextView.setTextAndKeepSelection(text);
- }
- } else {
- mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
- Gravity.RIGHT : Gravity.NO_GRAVITY);
- // This needs to be called before setType, which may call
- // requestFormData, and it needs to have the correct nodePointer.
- mWebTextView.setNodePointer(nodePointer);
- mWebTextView.setType(nativeFocusCandidateType());
- updateWebTextViewPadding();
- if (null == text) {
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "rebuildWebTextView null == text");
- }
- text = "";
- }
- mWebTextView.setTextAndKeepSelection(text);
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null && imm.isActive(mWebTextView)) {
- imm.restartInput(mWebTextView);
+ mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
+ Gravity.RIGHT : Gravity.NO_GRAVITY);
+ // This needs to be called before setType, which may call
+ // requestFormData, and it needs to have the correct nodePointer.
+ mWebTextView.setNodePointer(nodePointer);
+ mWebTextView.setType(nativeFocusCandidateType());
+ updateWebTextViewPadding();
+ if (null == text) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "rebuildWebTextView null == text");
}
+ text = "";
+ }
+ mWebTextView.setTextAndKeepSelection(text);
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null && imm.isActive(mWebTextView)) {
+ imm.restartInput(mWebTextView);
}
if (isFocused()) {
mWebTextView.requestFocus();
@@ -8120,19 +8103,7 @@ public class WebView extends AbsoluteLayout
// and representing the same node as the pointer.
if (inEditingMode() &&
mWebTextView.isSameTextField(msg.arg1)) {
- if (msg.getData().getBoolean("password")) {
- Spannable text = (Spannable) mWebTextView.getText();
- int start = Selection.getSelectionStart(text);
- int end = Selection.getSelectionEnd(text);
- mWebTextView.setInPassword(true);
- // Restore the selection, which may have been
- // ruined by setInPassword.
- Spannable pword =
- (Spannable) mWebTextView.getText();
- Selection.setSelection(pword, start, end);
- // If the text entry has created more events, ignore
- // this one.
- } else if (msg.arg2 == mTextGeneration) {
+ if (msg.arg2 == mTextGeneration) {
String text = (String) msg.obj;
if (null == text) {
text = "";
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index b7c1687..c4458df 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2817,9 +2817,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mPositionScroller.stop();
}
mTouchMode = TOUCH_MODE_OVERSCROLL;
+ mMotionX = (int) ev.getX();
mMotionY = mLastY = (int) ev.getY();
mMotionCorrection = 0;
mActivePointerId = ev.getPointerId(0);
+ mDirection = 0;
break;
}
@@ -2994,56 +2996,57 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mDirection = newDirection;
}
- if (mDirection != newDirection) {
- // Coming back to 'real' list scrolling
- incrementalDeltaY = -newScroll;
- mScrollY = 0;
- invalidateParentIfNeeded();
-
- // No need to do all this work if we're not going to move anyway
- if (incrementalDeltaY != 0) {
- trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
- }
-
- // Check to see if we are back in
- View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
- if (motionView != null) {
- mTouchMode = TOUCH_MODE_SCROLL;
-
- // We did not scroll the full amount. Treat this essentially like the
- // start of a new touch scroll
- final int motionPosition = findClosestMotionRow(y);
-
- mMotionCorrection = 0;
- motionView = getChildAt(motionPosition - mFirstPosition);
- mMotionViewOriginalTop = motionView.getTop();
- mMotionY = y;
- mMotionPosition = motionPosition;
- }
+ int overScrollDistance = -incrementalDeltaY;
+ if ((newScroll < 0 && oldScroll >= 0) || (newScroll > 0 && oldScroll <= 0)) {
+ overScrollDistance = -oldScroll;
+ incrementalDeltaY += overScrollDistance;
} else {
- overScrollBy(0, -incrementalDeltaY, 0, mScrollY, 0, 0,
+ incrementalDeltaY = 0;
+ }
+
+ if (overScrollDistance != 0) {
+ overScrollBy(0, overScrollDistance, 0, mScrollY, 0, 0,
0, mOverscrollDistance, true);
final int overscrollMode = getOverScrollMode();
if (overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
if (rawDeltaY > 0) {
- mEdgeGlowTop.onPull((float) -incrementalDeltaY / getHeight());
+ mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
} else if (rawDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) -incrementalDeltaY / getHeight());
+ mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
}
invalidate();
}
- if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
- // Don't allow overfling if we're at the edge.
- mVelocityTracker.clear();
+ }
+
+ if (incrementalDeltaY != 0) {
+ // Coming back to 'real' list scrolling
+ mScrollY = 0;
+ invalidateParentIfNeeded();
+
+ // No need to do all this work if we're not going to move anyway
+ if (incrementalDeltaY != 0) {
+ trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
}
+
+ mTouchMode = TOUCH_MODE_SCROLL;
+
+ // We did not scroll the full amount. Treat this essentially like the
+ // start of a new touch scroll
+ final int motionPosition = findClosestMotionRow(y);
+
+ mMotionCorrection = 0;
+ View motionView = getChildAt(motionPosition - mFirstPosition);
+ mMotionViewOriginalTop = motionView != null ? motionView.getTop() : 0;
+ mMotionY = y;
+ mMotionPosition = motionPosition;
}
mLastY = y;
mDirection = newDirection;
@@ -3320,12 +3323,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mScrollY = scrollY;
invalidateParentIfNeeded();
- if (clampedY) {
- // Velocity is broken by hitting the limit; don't start a fling off of this.
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
- }
awakenScrollBars();
}
}
@@ -3616,9 +3613,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
void startOverfling(int initialVelocity) {
- final int min = mScrollY > 0 ? Integer.MIN_VALUE : 0;
- final int max = mScrollY > 0 ? 0 : Integer.MAX_VALUE;
- mScroller.fling(0, mScrollY, 0, initialVelocity, 0, 0, min, max, 0, getHeight());
+ mScroller.fling(0, mScrollY, 0, initialVelocity, 0, 0,
+ Integer.MIN_VALUE, Integer.MAX_VALUE, 0, getHeight());
mTouchMode = TOUCH_MODE_OVERFLING;
invalidate();
post(this);
@@ -3768,10 +3764,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final OverScroller scroller = mScroller;
if (scroller.computeScrollOffset()) {
final int scrollY = mScrollY;
- final int deltaY = scroller.getCurrY() - scrollY;
+ final int currY = scroller.getCurrY();
+ final int deltaY = currY - scrollY;
if (overScrollBy(0, deltaY, 0, scrollY, 0, 0,
0, mOverflingDistance, false)) {
- startSpringback();
+ final boolean crossDown = scrollY <= 0 && currY > 0;
+ final boolean crossUp = scrollY >= 0 && currY < 0;
+ if (crossDown || crossUp) {
+ int velocity = (int) scroller.getCurrVelocity();
+ if (crossUp) velocity = -velocity;
+
+ // Don't flywheel from this; we're just continuing things.
+ scroller.abortAnimation();
+ start(velocity);
+ } else {
+ startSpringback();
+ }
} else {
invalidate();
post(this);
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index d85f8a4..45d73af 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -29,16 +29,7 @@ import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ActivityChooserModel;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListPopupWindow;
-import android.widget.PopupWindow;
-import android.widget.TextView;
import com.android.internal.R;
@@ -85,12 +76,22 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
/**
* The expand activities action button;
*/
- private final ImageButton mExpandActivityOverflowButton;
+ private final FrameLayout mExpandActivityOverflowButton;
+
+ /**
+ * The image for the expand activities action button;
+ */
+ private final ImageView mExpandActivityOverflowButtonImage;
/**
* The default activities action button;
*/
- private final ImageButton mDefaultActionButton;
+ private final FrameLayout mDefaultActivityButton;
+
+ /**
+ * The image for the default activities action button;
+ */
+ private final ImageView mDefaultActivityButtonImage;
/**
* The maximal width of the list popup.
@@ -185,13 +186,16 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
mActivityChooserContent = (LinearLayout) findViewById(R.id.activity_chooser_view_content);
- mDefaultActionButton = (ImageButton) findViewById(R.id.default_activity_button);
- mDefaultActionButton.setOnClickListener(mCallbacks);
- mDefaultActionButton.setOnLongClickListener(mCallbacks);
+ mDefaultActivityButton = (FrameLayout) findViewById(R.id.default_activity_button);
+ mDefaultActivityButton.setOnClickListener(mCallbacks);
+ mDefaultActivityButton.setOnLongClickListener(mCallbacks);
+ mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.image);
- mExpandActivityOverflowButton = (ImageButton) findViewById(R.id.expand_activities_button);
+ mExpandActivityOverflowButton = (FrameLayout) findViewById(R.id.expand_activities_button);
mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
- mExpandActivityOverflowButton.setImageDrawable(expandActivityOverflowButtonDrawable);
+ mExpandActivityOverflowButtonImage =
+ (ImageView) mExpandActivityOverflowButton.findViewById(R.id.image);
+ mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
mAdapter = new ActivityChooserViewAdapter();
mAdapter.registerDataSetObserver(new DataSetObserver() {
@@ -230,7 +234,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
* @param drawable The drawable.
*/
public void setExpandActivityOverflowButtonDrawable(Drawable drawable) {
- mExpandActivityOverflowButton.setImageDrawable(drawable);
+ mExpandActivityOverflowButtonImage.setImageDrawable(drawable);
}
/**
@@ -391,7 +395,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
private void updateButtons() {
final int activityCount = mAdapter.getActivityCount();
if (activityCount > 0) {
- mDefaultActionButton.setVisibility(VISIBLE);
+ mDefaultActivityButton.setVisibility(VISIBLE);
if (mAdapter.getCount() > 0) {
mExpandActivityOverflowButton.setEnabled(true);
} else {
@@ -399,9 +403,9 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
}
ResolveInfo activity = mAdapter.getDefaultActivity();
PackageManager packageManager = mContext.getPackageManager();
- mDefaultActionButton.setImageDrawable(activity.loadIcon(packageManager));
+ mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
} else {
- mDefaultActionButton.setVisibility(View.INVISIBLE);
+ mDefaultActivityButton.setVisibility(View.INVISIBLE);
mExpandActivityOverflowButton.setEnabled(false);
}
}
@@ -440,7 +444,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
// View.OnClickListener
public void onClick(View view) {
- if (view == mDefaultActionButton) {
+ if (view == mDefaultActivityButton) {
dismissPopup();
ResolveInfo defaultActivity = mAdapter.getDefaultActivity();
final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
@@ -457,7 +461,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
// OnLongClickListener#onLongClick
@Override
public boolean onLongClick(View view) {
- if (view == mDefaultActionButton) {
+ if (view == mDefaultActivityButton) {
if (mAdapter.getCount() > 0) {
mIsSelectingDefaultActivity = true;
showPopupUnchecked(mInitialActivityCount);
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 5eba1a0..0b0b812 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -34,12 +34,17 @@ import android.widget.RemoteViews.RemoteView;
/**
* FrameLayout is designed to block out an area on the screen to display
- * a single item. You can add multiple children to a FrameLayout and control their
- * position within the FrameLayout using {@link android.widget.FrameLayout.LayoutParams#gravity}.
- * Children are drawn in a stack, with the most recently added child on top.
- * The size of the frame layout is the size of its largest child (plus padding), visible
- * or not (if the FrameLayout's parent permits). Views that are GONE are used for sizing
- * only if {@link #setMeasureAllChildren(boolean) setMeasureAllChildren()}
+ * a single item. Generally, FrameLayout should be used to hold a single child view, because it can
+ * be difficult to organize child views in a way that's scalable to different screen sizes without
+ * the children overlapping each other. You can, however, add multiple children to a FrameLayout
+ * and control their position within the FrameLayout by assigning gravity to each child, using the
+ * <a href="FrameLayout.LayoutParams.html#attr_android:layout_gravity">{@code
+ * android:layout_gravity}</a> attribute.
+ * <p>Child views are drawn in a stack, with the most recently added child on top.
+ * The size of the FrameLayout is the size of its largest child (plus padding), visible
+ * or not (if the FrameLayout's parent permits). Views that are {@link android.view.View#GONE} are
+ * used for sizing
+ * only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()}
* is set to true.
*
* @attr ref android.R.styleable#FrameLayout_foreground
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 55b73df..91b19ed 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -221,6 +221,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
mCloseButton.setOnClickListener(mOnClickListener);
mSubmitButton.setOnClickListener(mOnClickListener);
mVoiceButton.setOnClickListener(mOnClickListener);
+ mQueryTextView.setOnClickListener(mOnClickListener);
mQueryTextView.addTextChangedListener(mTextWatcher);
mQueryTextView.setOnEditorActionListener(mOnEditorActionListener);
@@ -319,7 +320,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
// If it is not iconified, then give the focus to the text field
if (!isIconified()) {
boolean result = mQueryTextView.requestFocus(direction, previouslyFocusedRect);
- if (result) updateViewsVisibility(false);
+ if (result) {
+ updateViewsVisibility(false);
+ }
return result;
} else {
return super.requestFocus(direction, previouslyFocusedRect);
@@ -330,9 +333,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
@Override
public void clearFocus() {
mClearingFocus = true;
+ setImeVisibility(false);
super.clearFocus();
mQueryTextView.clearFocus();
- setImeVisibility(false);
mClearingFocus = false;
}
@@ -681,6 +684,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
onSubmitQuery();
} else if (v == mVoiceButton) {
onVoiceClicked();
+ } else if (v == mQueryTextView) {
+ forceSuggestionQuery();
}
}
};
@@ -1029,6 +1034,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
void onTextFocusChanged() {
updateViewsVisibility(isIconified());
updateFocusedState(mQueryTextView.hasFocus());
+ if (mQueryTextView.hasFocus()) {
+ forceSuggestionQuery();
+ }
}
@Override
@@ -1041,8 +1049,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
*/
@Override
public void onActionViewCollapsed() {
+ clearFocus();
+ updateViewsVisibility(true);
mQueryTextView.setText("");
- setIconified(true);
mExpandedInActionView = false;
}
@@ -1376,6 +1385,11 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
}
}
+ private void forceSuggestionQuery() {
+ mQueryTextView.doBeforeTextChanged();
+ mQueryTextView.doAfterTextChanged();
+ }
+
static boolean isLandscapeMode(Context context) {
return context.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a7324b0..127b6a3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -329,7 +329,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mTextEditPasteWindowLayout, mTextEditSidePasteWindowLayout;
private int mTextEditNoPasteWindowLayout, mTextEditSideNoPasteWindowLayout;
- private int mTextEditSuggestionsWindowLayout;
private int mTextEditSuggestionItemLayout;
private SuggestionsPopupWindow mSuggestionsPopupWindow;
private SuggestionRangeSpan mSuggestionRangeSpan;
@@ -830,10 +829,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mTextEditSideNoPasteWindowLayout = a.getResourceId(attr, 0);
break;
- case com.android.internal.R.styleable.TextView_textEditSuggestionsWindowLayout:
- mTextEditSuggestionsWindowLayout = a.getResourceId(attr, 0);
- break;
-
case com.android.internal.R.styleable.TextView_textEditSuggestionItemLayout:
mTextEditSuggestionItemLayout = a.getResourceId(attr, 0);
break;
@@ -8780,65 +8775,55 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private class SuggestionsPopupWindow implements OnClickListener {
private static final int MAX_NUMBER_SUGGESTIONS = 5;
private static final int NO_SUGGESTIONS = -1;
- private final PopupWindow mContainer;
- private ViewGroup mSuggestionViewGroup;
+ private final PopupWindow mPopupWindow;
+ private LinearLayout mSuggestionsContainer;
private WordIterator mSuggestionWordIterator;
private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan[0];
public SuggestionsPopupWindow() {
- mContainer = new PopupWindow(TextView.this.mContext, null,
+ mPopupWindow = new PopupWindow(TextView.this.mContext, null,
com.android.internal.R.attr.textSuggestionsWindowStyle);
- mContainer.setSplitTouchEnabled(true);
- mContainer.setClippingEnabled(false);
- mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+ mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+ mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+ mPopupWindow.setOutsideTouchable(true);
- mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
- mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
- }
+ mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+ mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
- private class SuggestionInfo {
- int suggestionStart, suggestionEnd; // range of suggestion item with replacement text
- int spanStart, spanEnd; // range in TextView where text should be inserted
- SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
- int suggestionIndex; // the index of the suggestion inside suggestionSpan
- }
+ mSuggestionsContainer = new LinearLayout(TextView.this.mContext);
+ mSuggestionsContainer.setOrientation(LinearLayout.VERTICAL);
- private void initSuggestionViewGroup() {
- if (mSuggestionViewGroup == null) {
- LayoutInflater inflater = (LayoutInflater) TextView.this.mContext.
- getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater inflater = (LayoutInflater) TextView.this.mContext.
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- if (inflater == null) {
- throw new IllegalArgumentException(
- "Unable to create TextEdit suggestion window inflater");
- }
+ if (inflater == null) {
+ throw new IllegalArgumentException(
+ "Unable to create inflater for TextEdit suggestions");
+ }
- View view = inflater.inflate(mTextEditSuggestionsWindowLayout, null);
+ // Inflate the suggestion items once and for all.
+ for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
+ View childView = inflater.inflate(mTextEditSuggestionItemLayout,
+ mSuggestionsContainer, false);
- if (! (view instanceof ViewGroup)) {
+ if (! (childView instanceof TextView)) {
throw new IllegalArgumentException(
- "Inflated TextEdit suggestion window is not a ViewGroup: " + view);
+ "Inflated TextEdit suggestion item is not a TextView: " + childView);
}
- mSuggestionViewGroup = (ViewGroup) view;
-
- // Inflate the suggestion items once and for all.
- for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
- View childView = inflater.inflate(mTextEditSuggestionItemLayout,
- mSuggestionViewGroup, false);
-
- if (! (childView instanceof TextView)) {
- throw new IllegalArgumentException(
- "Inflated TextEdit suggestion item is not a TextView: " + childView);
- }
+ childView.setTag(new SuggestionInfo());
+ mSuggestionsContainer.addView(childView);
+ childView.setOnClickListener(this);
+ }
- childView.setTag(new SuggestionInfo());
- mSuggestionViewGroup.addView(childView);
- childView.setOnClickListener(this);
- }
+ mPopupWindow.setContentView(mSuggestionsContainer);
+ }
- mContainer.setContentView(mSuggestionViewGroup);
- }
+ private class SuggestionInfo {
+ int suggestionStart, suggestionEnd; // range of suggestion item with replacement text
+ int spanStart, spanEnd; // range in TextView where text should be inserted
+ SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
+ int suggestionIndex; // the index of the suggestion inside suggestionSpan
}
public void show() {
@@ -8849,8 +8834,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
final int nbSpans = suggestionSpans.length;
- initSuggestionViewGroup();
-
int totalNbSuggestions = 0;
int spanUnionStart = mText.length();
int spanUnionEnd = 0;
@@ -8865,7 +8848,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
String[] suggestions = suggestionSpan.getSuggestions();
int nbSuggestions = suggestions.length;
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
- TextView textView = (TextView) mSuggestionViewGroup.getChildAt(
+ TextView textView = (TextView) mSuggestionsContainer.getChildAt(
totalNbSuggestions);
textView.setText(suggestions[suggestionIndex]);
SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
@@ -8885,7 +8868,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (totalNbSuggestions == 0) {
// TODO Replace by final text, use a dedicated layout, add a fade out timer...
- TextView textView = (TextView) mSuggestionViewGroup.getChildAt(0);
+ TextView textView = (TextView) mSuggestionsContainer.getChildAt(0);
textView.setText("No suggestions available");
SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
suggestionInfo.spanStart = NO_SUGGESTIONS;
@@ -8896,22 +8879,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
for (int i = 0; i < totalNbSuggestions; i++) {
- final TextView textView = (TextView) mSuggestionViewGroup.getChildAt(i);
+ final TextView textView = (TextView) mSuggestionsContainer.getChildAt(i);
highlightTextDifferences(textView, spanUnionStart, spanUnionEnd);
}
}
for (int i = 0; i < totalNbSuggestions; i++) {
- mSuggestionViewGroup.getChildAt(i).setVisibility(VISIBLE);
+ mSuggestionsContainer.getChildAt(i).setVisibility(VISIBLE);
}
for (int i = totalNbSuggestions; i < MAX_NUMBER_SUGGESTIONS; i++) {
- mSuggestionViewGroup.getChildAt(i).setVisibility(GONE);
+ mSuggestionsContainer.getChildAt(i).setVisibility(GONE);
}
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
final int screenWidth = displayMetrics.widthPixels;
final int screenHeight = displayMetrics.heightPixels;
- mSuggestionViewGroup.measure(
+ mSuggestionsContainer.measure(
View.MeasureSpec.makeMeasureSpec(screenWidth, View.MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(screenHeight, View.MeasureSpec.AT_MOST));
@@ -9071,11 +9054,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if ((mText instanceof Editable) && mSuggestionRangeSpan != null) {
((Editable) mText).removeSpan(mSuggestionRangeSpan);
}
- mContainer.dismiss();
+ mPopupWindow.dismiss();
}
public boolean isShowing() {
- return mContainer.isShowing();
+ return mPopupWindow.isShowing();
}
@Override
@@ -9139,7 +9122,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
void positionAtCursor() {
- View contentView = mContainer.getContentView();
+ View contentView = mPopupWindow.getContentView();
int width = contentView.getMeasuredWidth();
int height = contentView.getMeasuredHeight();
final int offset = TextView.this.getSelectionStart();
@@ -9173,7 +9156,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
coords[0] = Math.min(displayMetrics.widthPixels - width, coords[0]);
coords[0] = Math.max(0, coords[0]);
- mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
+ mPopupWindow.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
}
}
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 9ae7def..1531946 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -1,22 +1,9 @@
package com.android.internal.content;
-import android.content.pm.PackageManager;
import android.os.Build;
-import android.os.FileUtils;
-import android.os.SystemProperties;
-import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Enumeration;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipFile;
/**
* Native libraries helper.
@@ -28,270 +15,22 @@ public class NativeLibraryHelper {
private static final boolean DEBUG_NATIVE = false;
- /*
- * The following constants are returned by listPackageSharedLibsForAbiLI
- * to indicate if native shared libraries were found in the package.
- * Values are:
- * PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed
- * PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package
- * PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found
- * in package (and not installed)
- *
- */
- private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0;
- private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1;
- private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2;
+ private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2);
- // Directory in the APK that holds all the native shared libraries.
- private static final String APK_LIB = "lib/";
- private static final int APK_LIB_LENGTH = APK_LIB.length();
-
- // Prefix that native shared libraries must have.
- private static final String LIB_PREFIX = "lib";
- private static final int LIB_PREFIX_LENGTH = LIB_PREFIX.length();
-
- // Suffix that the native shared libraries must have.
- private static final String LIB_SUFFIX = ".so";
- private static final int LIB_SUFFIX_LENGTH = LIB_SUFFIX.length();
-
- // Name of the GDB binary.
- private static final String GDBSERVER = "gdbserver";
-
- // the minimum length of a valid native shared library of the form
- // lib/<something>/lib<name>.so.
- private static final int MIN_ENTRY_LENGTH = APK_LIB_LENGTH + 2 + LIB_PREFIX_LENGTH + 1
- + LIB_SUFFIX_LENGTH;
-
- /*
- * Find all files of the form lib/<cpuAbi>/lib<name>.so in the .apk
- * and add them to a list to be installed later.
- *
- * NOTE: this method may throw an IOException if the library cannot
- * be copied to its final destination, e.g. if there isn't enough
- * room left on the data partition, or a ZipException if the package
- * file is malformed.
- */
- private static int listPackageSharedLibsForAbiLI(ZipFile zipFile,
- String cpuAbi, List<Pair<ZipEntry, String>> libEntries) throws IOException,
- ZipException {
- final int cpuAbiLen = cpuAbi.length();
- boolean hasNativeLibraries = false;
- boolean installedNativeLibraries = false;
-
- if (DEBUG_NATIVE) {
- Slog.d(TAG, "Checking " + zipFile.getName() + " for shared libraries of CPU ABI type "
- + cpuAbi);
- }
-
- Enumeration<? extends ZipEntry> entries = zipFile.entries();
-
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
-
- // skip directories
- if (entry.isDirectory()) {
- continue;
- }
- String entryName = entry.getName();
-
- /*
- * Check that the entry looks like lib/<something>/lib<name>.so
- * here, but don't check the ABI just yet.
- *
- * - must be sufficiently long
- * - must end with LIB_SUFFIX, i.e. ".so"
- * - must start with APK_LIB, i.e. "lib/"
- */
- if (entryName.length() < MIN_ENTRY_LENGTH || !entryName.endsWith(LIB_SUFFIX)
- || !entryName.startsWith(APK_LIB)) {
- continue;
- }
-
- // file name must start with LIB_PREFIX, i.e. "lib"
- int lastSlash = entryName.lastIndexOf('/');
-
- if (lastSlash < 0
- || !entryName.regionMatches(lastSlash + 1, LIB_PREFIX, 0, LIB_PREFIX_LENGTH)) {
- continue;
- }
-
- hasNativeLibraries = true;
-
- // check the cpuAbi now, between lib/ and /lib<name>.so
- if (lastSlash != APK_LIB_LENGTH + cpuAbiLen
- || !entryName.regionMatches(APK_LIB_LENGTH, cpuAbi, 0, cpuAbiLen))
- continue;
-
- /*
- * Extract the library file name, ensure it doesn't contain
- * weird characters. we're guaranteed here that it doesn't contain
- * a directory separator though.
- */
- String libFileName = entryName.substring(lastSlash+1);
- if (!FileUtils.isFilenameSafe(new File(libFileName))) {
- continue;
- }
-
- installedNativeLibraries = true;
-
- if (DEBUG_NATIVE) {
- Log.d(TAG, "Caching shared lib " + entry.getName());
- }
-
- libEntries.add(Pair.create(entry, libFileName));
- }
- if (!hasNativeLibraries)
- return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
-
- if (!installedNativeLibraries)
- return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH;
-
- return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
+ public static long sumNativeBinariesLI(File apkFile) {
+ final String cpuAbi = Build.CPU_ABI;
+ final String cpuAbi2 = Build.CPU_ABI2;
+ return nativeSumNativeBinaries(apkFile.getPath(), cpuAbi, cpuAbi2);
}
- /*
- * Find the gdbserver executable program in a package at
- * lib/<cpuAbi>/gdbserver and add it to the list of binaries
- * to be copied out later.
- *
- * Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success,
- * or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise.
- */
- private static int listPackageGdbServerLI(ZipFile zipFile, String cpuAbi,
- List<Pair<ZipEntry, String>> nativeFiles) throws IOException, ZipException {
- final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER;
-
- Enumeration<? extends ZipEntry> entries = zipFile.entries();
-
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
- // skip directories
- if (entry.isDirectory()) {
- continue;
- }
- String entryName = entry.getName();
-
- if (!entryName.equals(apkGdbServerPath)) {
- continue;
- }
-
- if (false) {
- Log.d(TAG, "Found gdbserver: " + entry.getName());
- }
+ private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath,
+ String cpuAbi, String cpuAbi2);
- final String installGdbServerPath = GDBSERVER;
- nativeFiles.add(Pair.create(entry, installGdbServerPath));
-
- return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
- }
- return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
- }
-
- /*
- * Examine shared libraries stored in the APK as
- * lib/<cpuAbi>/lib<name>.so and add them to a list to be copied
- * later.
- *
- * This function will first try the main CPU ABI defined by Build.CPU_ABI
- * (which corresponds to ro.product.cpu.abi), and also try an alternate
- * one if ro.product.cpu.abi2 is defined.
- */
- public static int listPackageNativeBinariesLI(ZipFile zipFile,
- List<Pair<ZipEntry, String>> nativeFiles) throws ZipException, IOException {
- String cpuAbi = Build.CPU_ABI;
-
- int result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi, nativeFiles);
-
- /*
- * Some architectures are capable of supporting several CPU ABIs
- * for example, 'armeabi-v7a' also supports 'armeabi' native code
- * this is indicated by the definition of the ro.product.cpu.abi2
- * system property.
- *
- * only scan the package twice in case of ABI mismatch
- */
- if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
- final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2", null);
- if (cpuAbi2 != null) {
- result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi2, nativeFiles);
- }
-
- if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
- Slog.w(TAG, "Native ABI mismatch from package file");
- return PackageManager.INSTALL_FAILED_INVALID_APK;
- }
-
- if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
- cpuAbi = cpuAbi2;
- }
- }
-
- /*
- * Debuggable packages may have gdbserver embedded, so add it to
- * the list to the list of items to be extracted (as lib/gdbserver)
- * into the application's native library directory later.
- */
- if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
- listPackageGdbServerLI(zipFile, cpuAbi, nativeFiles);
- }
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- public static int copyNativeBinariesLI(File scanFile, File sharedLibraryDir) {
- /*
- * Check all the native files that need to be copied and add
- * that to the container size.
- */
- ZipFile zipFile;
- try {
- zipFile = new ZipFile(scanFile);
-
- List<Pair<ZipEntry, String>> nativeFiles = new LinkedList<Pair<ZipEntry, String>>();
-
- NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles);
-
- final int N = nativeFiles.size();
-
- for (int i = 0; i < N; i++) {
- final Pair<ZipEntry, String> entry = nativeFiles.get(i);
-
- File destFile = new File(sharedLibraryDir, entry.second);
- copyNativeBinaryLI(zipFile, entry.first, sharedLibraryDir, destFile);
- }
- zipFile.close();
- } catch (ZipException e) {
- Slog.w(TAG, "Failed to extract data from package file", e);
- return PackageManager.INSTALL_FAILED_INVALID_APK;
- } catch (IOException e) {
- Slog.w(TAG, "Failed to cache package shared libs", e);
- return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
-
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- private static void copyNativeBinaryLI(ZipFile zipFile, ZipEntry entry,
- File binaryDir, File binaryFile) throws IOException {
- InputStream inputStream = zipFile.getInputStream(entry);
- try {
- File tempFile = File.createTempFile("tmp", "tmp", binaryDir);
- String tempFilePath = tempFile.getPath();
- // XXX package manager can't change owner, so the executable files for
- // now need to be left as world readable and owned by the system.
- if (!FileUtils.copyToFile(inputStream, tempFile)
- || !tempFile.setLastModified(entry.getTime())
- || FileUtils.setPermissions(tempFilePath, FileUtils.S_IRUSR | FileUtils.S_IWUSR
- | FileUtils.S_IRGRP | FileUtils.S_IXUSR | FileUtils.S_IXGRP
- | FileUtils.S_IXOTH | FileUtils.S_IROTH, -1, -1) != 0
- || !tempFile.renameTo(binaryFile)) {
- // Failed to properly write file.
- tempFile.delete();
- throw new IOException("Couldn't create cached binary " + binaryFile + " in "
- + binaryDir);
- }
- } finally {
- inputStream.close();
- }
+ public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) {
+ final String cpuAbi = Build.CPU_ABI;
+ final String cpuAbi2 = Build.CPU_ABI2;
+ return nativeCopyNativeBinaries(apkFile.getPath(), sharedLibraryDir.getPath(), cpuAbi,
+ cpuAbi2);
}
// Convenience method to call removeNativeBinariesFromDirLI(File)
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 6ec186d..16336e0 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -474,7 +474,7 @@ public class ZygoteInit {
String args[] = {
"--setuid=1000",
"--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
+ "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index bf2965b..bff621c 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -36,8 +36,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
private boolean mReserveOverflow;
private ActionMenuPresenter mPresenter;
- private boolean mUpdateContentsBeforeMeasure;
private boolean mFormatItems;
+ private int mFormatItemsWidth;
private int mMinCellSize;
private int mMeasuredExtraWidth;
@@ -71,19 +71,21 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
@Override
- public void requestLayout() {
- // Layout can influence how many action items fit.
- mUpdateContentsBeforeMeasure = true;
- super.requestLayout();
- }
-
- @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// If we've been given an exact size to match, apply special formatting during layout.
+ final boolean wasFormatted = mFormatItems;
mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
- if (mUpdateContentsBeforeMeasure && mMenu != null) {
+
+ if (wasFormatted != mFormatItems) {
+ mFormatItemsWidth = 0; // Reset this when switching modes
+ }
+
+ // Special formatting can change whether items can fit as action buttons.
+ // Kick the menu and update presenters when this changes.
+ final int widthSize = MeasureSpec.getMode(widthMeasureSpec);
+ if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) {
+ mFormatItemsWidth = widthSize;
mMenu.onItemsChanged(true);
- mUpdateContentsBeforeMeasure = false;
}
if (mFormatItems) {
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 159b3da..19cbe25 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -27,6 +27,7 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
+import android.util.Log;
import android.util.SparseArray;
import android.view.ActionProvider;
import android.view.ContextMenu.ContextMenuInfo;
@@ -47,7 +48,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* standard menu UI.
*/
public class MenuBuilder implements Menu {
- private static final String LOGTAG = "MenuBuilder";
+ private static final String TAG = "MenuBuilder";
private static final String PRESENTER_KEY = "android:menu:presenters";
private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates";
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index b0a002d..8b53bb8 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -563,7 +563,7 @@ public final class MenuItemImpl implements MenuItem {
public MenuItem setActionView(int resId) {
final Context context = mMenu.getContext();
final LayoutInflater inflater = LayoutInflater.from(context);
- setActionView(inflater.inflate(resId, new LinearLayout(context)));
+ setActionView(inflater.inflate(resId, new LinearLayout(context), false));
return this;
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 09262e0..468f28e 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1323,11 +1323,18 @@ public class ActionBarView extends AbsActionBarView {
if (mExpandedActionView instanceof CollapsibleActionView) {
((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
}
+
return true;
}
@Override
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ // Do this before detaching the actionview from the hierarchy, in case
+ // it needs to dismiss the soft keyboard, etc.
+ if (mExpandedActionView instanceof CollapsibleActionView) {
+ ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
+ }
+
removeView(mExpandedActionView);
removeView(mExpandedHomeLayout);
if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0) {
@@ -1349,16 +1356,12 @@ public class ActionBarView extends AbsActionBarView {
if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
mCustomNavView.setVisibility(VISIBLE);
}
- View collapsedView = mExpandedActionView;
mExpandedActionView = null;
mExpandedHomeLayout.setIcon(null);
mCurrentExpandedItem = null;
requestLayout();
item.setActionViewExpanded(false);
- if (collapsedView instanceof CollapsibleActionView) {
- ((CollapsibleActionView) collapsedView).onActionViewCollapsed();
- }
return true;
}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 04bb689..94990b6 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -45,7 +45,7 @@ import com.android.internal.R;
*/
public class MultiWaveView extends View {
private static final String TAG = "MultiWaveView";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
// Wave state machine
private static final int STATE_IDLE = 0;