summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.xml46
-rw-r--r--core/java/android/app/Activity.java22
-rw-r--r--core/java/android/app/ActivityThread.java144
-rw-r--r--core/java/android/hardware/Camera.java45
-rw-r--r--core/java/android/provider/Downloads.java9
-rw-r--r--core/java/android/view/DragEvent.java17
-rw-r--r--core/java/android/view/View.java23
-rw-r--r--core/java/android/view/ViewRoot.java14
-rw-r--r--core/java/android/webkit/WebView.java43
-rw-r--r--core/java/android/widget/TextView.java5
-rw-r--r--core/java/com/android/internal/os/SamplingProfilerIntegration.java69
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--docs/html/resources/dashboard/platform-versions.jd36
-rwxr-xr-xpackages/DefaultContainerService/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java2
-rw-r--r--services/java/com/android/server/WindowManagerService.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java81
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java89
20 files changed, 549 insertions, 121 deletions
diff --git a/api/current.xml b/api/current.xml
index 9fc6e3ede857..4f9ba23a8430 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -23228,6 +23228,17 @@
<parameter name="exitAnim" type="int">
</parameter>
</method>
+<method name="recreate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="registerForContextMenu"
return="void"
abstract="false"
@@ -89752,6 +89763,17 @@
visibility="public"
>
</method>
+<method name="getPreferredPreviewSizeForVideo"
+ return="android.hardware.Camera.Size"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getPreviewFormat"
return="int"
abstract="false"
@@ -89941,6 +89963,17 @@
visibility="public"
>
</method>
+<method name="getSupportedVideoSizes"
+ return="java.util.List&lt;android.hardware.Camera.Size&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSupportedWhiteBalance"
return="java.util.List&lt;java.lang.String&gt;"
abstract="false"
@@ -194856,6 +194889,17 @@
visibility="public"
>
</method>
+<method name="getLocalState"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getResult"
return="boolean"
abstract="false"
@@ -208857,6 +208901,8 @@
</parameter>
<parameter name="myWindowOnly" type="boolean">
</parameter>
+<parameter name="myLocalState" type="java.lang.Object">
+</parameter>
</method>
<method name="unscheduleDrawable"
return="void"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6b619fb5567d..0a2e031dd74b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -42,6 +42,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.text.Selection;
@@ -78,6 +79,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* An activity is a single, focused thing that the user can do. Almost all
@@ -842,8 +844,6 @@ public class Activity extends ContextThemeWrapper
* @see #onPostCreate
*/
protected void onCreate(Bundle savedInstanceState) {
- mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowNoDisplay, false);
if (mLastNonConfigurationInstances != null) {
mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
}
@@ -3509,6 +3509,22 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Cause this Activity to be recreated with a new instance. This results
+ * in essentially the same flow as when the Activity is created due to
+ * a configuration change -- the current instance will go through its
+ * lifecycle to {@link #onDestroy} and a new instance then created after it.
+ */
+ public void recreate() {
+ if (mParent != null) {
+ throw new IllegalStateException("Can only be called on top-level activity");
+ }
+ if (Looper.myLooper() != mMainThread.getLooper()) {
+ throw new IllegalStateException("Must be called from main thread");
+ }
+ mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, false);
+ }
+
+ /**
* Call this when your activity is done and should be closed. The
* ActivityResult is propagated back to whoever launched you via
* onActivityResult().
@@ -4262,6 +4278,8 @@ public class Activity extends ContextThemeWrapper
final void performCreate(Bundle icicle) {
onCreate(icicle);
+ mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c0714e3bba25..a8f08c2df10e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -224,6 +224,11 @@ public final class ActivityThread {
boolean startsNotResumed;
boolean isForward;
+ int pendingConfigChanges;
+ boolean onlyLocalRequest;
+
+ View mPendingRemoveWindow;
+ WindowManager mPendingRemoveWindowManager;
ActivityClientRecord() {
parent = null;
@@ -444,19 +449,8 @@ public final class ActivityThread {
public final void scheduleRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config) {
- ActivityClientRecord r = new ActivityClientRecord();
-
- r.token = token;
- r.pendingResults = pendingResults;
- r.pendingIntents = pendingNewIntents;
- r.startsNotResumed = notResumed;
- r.createdConfig = config;
-
- synchronized (mPackages) {
- mRelaunchingActivities.add(r);
- }
-
- queueOrSendMessage(H.RELAUNCH_ACTIVITY, r, configChanges);
+ requestRelaunchActivity(token, pendingResults, pendingNewIntents,
+ configChanges, notResumed, config, true);
}
public final void scheduleNewIntent(List<Intent> intents, IBinder token) {
@@ -981,7 +975,7 @@ public final class ActivityThread {
} break;
case RELAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
- handleRelaunchActivity(r, msg.arg1);
+ handleRelaunchActivity(r);
} break;
case PAUSE_ACTIVITY:
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
@@ -2183,6 +2177,19 @@ public final class ActivityThread {
return r;
}
+ final void cleanUpPendingRemoveWindows(ActivityClientRecord r) {
+ if (r.mPendingRemoveWindow != null) {
+ r.mPendingRemoveWindowManager.removeViewImmediate(r.mPendingRemoveWindow);
+ IBinder wtoken = r.mPendingRemoveWindow.getWindowToken();
+ if (wtoken != null) {
+ WindowManagerImpl.getDefault().closeAll(wtoken,
+ r.activity.getClass().getName(), "Activity");
+ }
+ }
+ r.mPendingRemoveWindow = null;
+ r.mPendingRemoveWindowManager = null;
+ }
+
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
@@ -2235,6 +2242,9 @@ public final class ActivityThread {
r.hideForNow = true;
}
+ // Get rid of anything left hanging around.
+ cleanUpPendingRemoveWindows(r);
+
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible
@@ -2267,11 +2277,14 @@ public final class ActivityThread {
}
}
- r.nextIdle = mNewActivities;
- mNewActivities = r;
- if (localLOGV) Slog.v(
- TAG, "Scheduling idle handler for " + r);
- Looper.myQueue().addIdleHandler(new Idler());
+ if (!r.onlyLocalRequest) {
+ r.nextIdle = mNewActivities;
+ mNewActivities = r;
+ if (localLOGV) Slog.v(
+ TAG, "Scheduling idle handler for " + r);
+ Looper.myQueue().addIdleHandler(new Idler());
+ }
+ r.onlyLocalRequest = false;
} else {
// If an exception was thrown when trying to resume, then
@@ -2728,6 +2741,7 @@ public final class ActivityThread {
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance);
if (r != null) {
+ cleanUpPendingRemoveWindows(r);
WindowManager wm = r.activity.getWindowManager();
View v = r.activity.mDecor;
if (v != null) {
@@ -2736,16 +2750,31 @@ public final class ActivityThread {
}
IBinder wtoken = v.getWindowToken();
if (r.activity.mWindowAdded) {
- wm.removeViewImmediate(v);
+ if (r.onlyLocalRequest) {
+ // Hold off on removing this until the new activity's
+ // window is being added.
+ r.mPendingRemoveWindow = v;
+ r.mPendingRemoveWindowManager = wm;
+ } else {
+ wm.removeViewImmediate(v);
+ }
}
- if (wtoken != null) {
+ if (wtoken != null && r.mPendingRemoveWindow == null) {
WindowManagerImpl.getDefault().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
}
r.activity.mDecor = null;
}
- WindowManagerImpl.getDefault().closeAll(token,
- r.activity.getClass().getName(), "Activity");
+ if (r.mPendingRemoveWindow == null) {
+ // If we are delaying the removal of the activity window, then
+ // we can't clean up all windows here. Note that we can't do
+ // so later either, which means any windows that aren't closed
+ // by the app will leak. Well we try to warning them a lot
+ // about leaking windows, because that is a bug, so if they are
+ // using this recreate facility then they get to live with leaks.
+ WindowManagerImpl.getDefault().closeAll(token,
+ r.activity.getClass().getName(), "Activity");
+ }
// Mocked out contexts won't be participating in the normal
// process lifecycle, but if we're running with a proper
@@ -2766,17 +2795,70 @@ public final class ActivityThread {
}
}
- private final void handleRelaunchActivity(ActivityClientRecord tmp, int configChanges) {
+ public final void requestRelaunchActivity(IBinder token,
+ List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
+ int configChanges, boolean notResumed, Configuration config,
+ boolean fromServer) {
+ ActivityClientRecord target = null;
+
+ synchronized (mPackages) {
+ for (int i=0; i<mRelaunchingActivities.size(); i++) {
+ ActivityClientRecord r = mRelaunchingActivities.get(i);
+ if (r.token == token) {
+ target = r;
+ if (pendingResults != null) {
+ if (r.pendingResults != null) {
+ r.pendingResults.addAll(pendingResults);
+ } else {
+ r.pendingResults = pendingResults;
+ }
+ }
+ if (pendingNewIntents != null) {
+ if (r.pendingIntents != null) {
+ r.pendingIntents.addAll(pendingNewIntents);
+ } else {
+ r.pendingIntents = pendingNewIntents;
+ }
+ }
+ break;
+ }
+ }
+
+ if (target == null) {
+ target = new ActivityClientRecord();
+ target.token = token;
+ target.pendingResults = pendingResults;
+ target.pendingIntents = pendingNewIntents;
+ if (!fromServer) {
+ ActivityClientRecord existing = mActivities.get(token);
+ if (existing != null) {
+ target.startsNotResumed = existing.paused;
+ }
+ target.onlyLocalRequest = true;
+ }
+ mRelaunchingActivities.add(target);
+ queueOrSendMessage(H.RELAUNCH_ACTIVITY, target);
+ }
+
+ if (fromServer) {
+ target.startsNotResumed = notResumed;
+ target.onlyLocalRequest = false;
+ }
+ if (config != null) {
+ target.createdConfig = config;
+ }
+ target.pendingConfigChanges |= configChanges;
+ }
+ }
+
+ private final void handleRelaunchActivity(ActivityClientRecord tmp) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
Configuration changedConfig = null;
+ int configChanges = 0;
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
- + tmp.token + " with configChanges=0x"
- + Integer.toHexString(configChanges));
-
// First: make sure we have the most recent configuration and most
// recent version of the activity, or skip it if some previous call
// had taken a more recent version.
@@ -2788,6 +2870,7 @@ public final class ActivityThread {
ActivityClientRecord r = mRelaunchingActivities.get(i);
if (r.token == token) {
tmp = r;
+ configChanges |= tmp.pendingConfigChanges;
mRelaunchingActivities.remove(i);
i--;
N--;
@@ -2799,6 +2882,10 @@ public final class ActivityThread {
return;
}
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
+ + tmp.token + " with configChanges=0x"
+ + Integer.toHexString(configChanges));
+
if (mPendingConfiguration != null) {
changedConfig = mPendingConfiguration;
mPendingConfiguration = null;
@@ -2834,6 +2921,7 @@ public final class ActivityThread {
}
r.activity.mConfigChangeFlags |= configChanges;
+ r.onlyLocalRequest = tmp.onlyLocalRequest;
Intent currentIntent = r.activity.mIntent;
Bundle savedState = null;
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index f3b2c81a72f4..fe4b900510fe 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1021,6 +1021,9 @@ public class Camera {
private static final String KEY_ZOOM_SUPPORTED = "zoom-supported";
private static final String KEY_SMOOTH_ZOOM_SUPPORTED = "smooth-zoom-supported";
private static final String KEY_FOCUS_DISTANCES = "focus-distances";
+ private static final String KEY_VIDEO_SIZE = "video-size";
+ private static final String KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO =
+ "preferred-preview-size-for-video";
// Parameter key suffix for supported values.
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -1398,7 +1401,7 @@ public class Camera {
/**
* Returns the dimensions setting for preview pictures.
*
- * @return a Size object with the height and width setting
+ * @return a Size object with the width and height setting
* for the preview picture
*/
public Size getPreviewSize() {
@@ -1418,6 +1421,46 @@ public class Camera {
}
/**
+ * Gets the supported video frame sizes that can be used by
+ * MediaRecorder.
+ *
+ * If the returned list is not null, the returned list will contain at
+ * least one Size and one of the sizes in the returned list must be
+ * passed to MediaRecorder.setVideoSize() for camcorder application if
+ * camera is used as the video source. In this case, the size of the
+ * preview can be different from the resolution of the recorded video
+ * during video recording.
+ *
+ * @return a list of Size object if camera has separate preview and
+ * video output; otherwise, null is returned.
+ * @see #getPreferredPreviewSizeForVideo()
+ */
+ public List<Size> getSupportedVideoSizes() {
+ String str = get(KEY_VIDEO_SIZE + SUPPORTED_VALUES_SUFFIX);
+ return splitSize(str);
+ }
+
+ /**
+ * Returns the preferred or recommended preview size (width and height)
+ * in pixels for video recording. Camcorder applications should
+ * set the preview size to a value that is not larger than the
+ * preferred preview size. In other words, the product of the width
+ * and height of the preview size should not be larger than that of
+ * the preferred preview size. In addition, we recommend to choose a
+ * preview size that has the same aspect ratio as the resolution of
+ * video to be recorded.
+ *
+ * @return the preferred preview size (width and height) in pixels for
+ * video recording if getSupportedVideoSizes() does not return
+ * null; otherwise, null is returned.
+ * @see #getSupportedVideoSizes()
+ */
+ public Size getPreferredPreviewSizeForVideo() {
+ String pair = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ return strToSize(pair);
+ }
+
+ /**
* Sets the dimensions for EXIF thumbnail in Jpeg picture. If
* applications set both width and height to 0, EXIF will not contain
* thumbnail.
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 683e60390031..b2b8c5af9df2 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -51,7 +51,14 @@ public final class Downloads {
"android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED";
/**
- * The permission to directly access the download manager's cache directory
+ * The permission to access the all the downloads in the manager.
+ */
+ public static final String PERMISSION_ACCESS_ALL =
+ "android.permission.ACCESS_ALL_DOWNLOADS";
+
+ /**
+ * The permission to directly access the download manager's cache
+ * directory
*/
public static final String PERMISSION_CACHE = "android.permission.ACCESS_CACHE_FILESYSTEM";
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 07e87d673875..6634f008ecc0 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -29,6 +29,7 @@ public class DragEvent implements Parcelable {
float mX, mY;
ClipDescription mClipDescription;
ClipData mClipData;
+ Object mLocalState;
boolean mDragResult;
private DragEvent mNext;
@@ -139,11 +140,11 @@ public static final int ACTION_DRAG_EXITED = 6;
}
static DragEvent obtain() {
- return DragEvent.obtain(0, 0f, 0f, null, null, false);
+ return DragEvent.obtain(0, 0f, 0f, null, null, null, false);
}
/** @hide */
- public static DragEvent obtain(int action, float x, float y,
+ public static DragEvent obtain(int action, float x, float y, Object localState,
ClipDescription description, ClipData data, boolean result) {
final DragEvent ev;
synchronized (gRecyclerLock) {
@@ -167,7 +168,7 @@ public static final int ACTION_DRAG_EXITED = 6;
/** @hide */
public static DragEvent obtain(DragEvent source) {
- return obtain(source.mAction, source.mX, source.mY,
+ return obtain(source.mAction, source.mX, source.mY, source.mLocalState,
source.mClipDescription, source.mClipData, source.mDragResult);
}
@@ -218,6 +219,15 @@ public static final int ACTION_DRAG_EXITED = 6;
}
/**
+ * Provides the local state object passed as the {@code myLocalState} parameter to
+ * View.startDrag(). The object will always be null here if the application receiving
+ * the DragEvent is not the one that started the drag.
+ */
+ public Object getLocalState() {
+ return mLocalState;
+ }
+
+ /**
* Provides an indication of whether the drag operation concluded successfully.
* This method is only available on ACTION_DRAG_ENDED events.
* @return {@code true} if the drag operation ended with an accepted drop; {@code false}
@@ -249,6 +259,7 @@ public static final int ACTION_DRAG_EXITED = 6;
mClipData = null;
mClipDescription = null;
+ mLocalState = null;
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f135fccc5d60..ea237e3dbc52 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10081,9 +10081,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* onProvideThumbnailMetrics() and onDrawThumbnail() methods happen, then the drag
* operation is handed over to the OS.
* !!! TODO: real docs
+ *
+ * @param data !!! TODO
+ * @param thumbBuilder !!! TODO
+ * @param myWindowOnly When {@code true}, indicates that the drag operation should be
+ * restricted to the calling application. In this case only the calling application
+ * will see any DragEvents related to this drag operation.
+ * @param myLocalState An arbitrary object that will be passed as part of every DragEvent
+ * delivered to the calling application during the course of the current drag operation.
+ * This object is private to the application that called startDrag(), and is not
+ * visible to other applications. It provides a lightweight way for the application to
+ * propagate information from the initiator to the recipient of a drag within its own
+ * application; for example, to help disambiguate between 'copy' and 'move' semantics.
+ * @return {@code true} if the drag operation was initiated successfully; {@code false} if
+ * an error prevented the drag from taking place.
*/
public final boolean startDrag(ClipData data, DragThumbnailBuilder thumbBuilder,
- boolean myWindowOnly) {
+ boolean myWindowOnly, Object myLocalState) {
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "startDrag: data=" + data + " local=" + myWindowOnly);
}
@@ -10117,8 +10131,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
surface.unlockCanvasAndPost(canvas);
}
+ final ViewRoot root = getViewRoot();
+
+ // Cache the local state object for delivery with DragEvents
+ root.setLocalDragState(myLocalState);
+
// repurpose 'thumbSize' for the last touch point
- getViewRoot().getLastTouchPoint(thumbSize);
+ root.getLastTouchPoint(thumbSize);
okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token,
(float) thumbSize.x, (float) thumbSize.y,
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 77083a902112..17d413a5eb44 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -228,6 +228,7 @@ public final class ViewRoot extends Handler implements ViewParent,
/* Drag/drop */
ClipDescription mDragDescription;
View mCurrentDragView;
+ Object mLocalDragState;
final PointF mDragPoint = new PointF();
final PointF mLastTouchPoint = new PointF();
@@ -2680,6 +2681,10 @@ public final class ViewRoot extends Handler implements ViewParent,
}
/* drag/drop */
+ void setLocalDragState(Object obj) {
+ mLocalDragState = obj;
+ }
+
private void handleDragEvent(DragEvent event) {
// From the root, only drag start/end/location are dispatched. entered/exited
// are determined and dispatched by the viewgroup hierarchy, who then report
@@ -2738,7 +2743,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
- // Report the drop result if necessary
+ // Report the drop result when we're done
if (what == DragEvent.ACTION_DROP) {
try {
Log.i(TAG, "Reporting drop result: " + result);
@@ -2747,6 +2752,12 @@ public final class ViewRoot extends Handler implements ViewParent,
Log.e(TAG, "Unable to report drop result");
}
}
+
+ // When the drag operation ends, release any local state object
+ // that may have been in use
+ if (what == DragEvent.ACTION_DRAG_ENDED) {
+ setLocalDragState(null);
+ }
}
}
event.recycle();
@@ -3063,6 +3074,7 @@ public final class ViewRoot extends Handler implements ViewParent,
} else {
what = DISPATCH_DRAG_EVENT;
}
+ event.mLocalState = mLocalDragState; // only present when this app called startDrag()
Message msg = obtainMessage(what, event);
sendMessage(msg);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 27a4b6da9563..be475ca31238 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -314,6 +314,17 @@ public class WebView extends AbsoluteLayout
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener {
+ private class InnerGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
+ public void onGlobalLayout() {
+ if (isShown()) {
+ setGLRectViewport();
+ }
+ }
+ }
+
+ // The listener to capture global layout change event.
+ private InnerGlobalLayoutListener mListener = null;
+
// if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing
// the screen all-the-time. Good for profiling our drawing code
static private final boolean AUTO_REDRAW_HACK = false;
@@ -4689,6 +4700,11 @@ public class WebView extends AbsoluteLayout
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (hasWindowFocus()) setActive(true);
+ final ViewTreeObserver treeObserver = getViewTreeObserver();
+ if (treeObserver != null && mListener == null) {
+ mListener = new InnerGlobalLayoutListener();
+ treeObserver.addOnGlobalLayoutListener(mListener);
+ }
}
@Override
@@ -4696,6 +4712,13 @@ public class WebView extends AbsoluteLayout
clearHelpers();
mZoomManager.dismissZoomPicker();
if (hasWindowFocus()) setActive(false);
+
+ final ViewTreeObserver treeObserver = getViewTreeObserver();
+ if (treeObserver != null && mListener != null) {
+ treeObserver.removeGlobalOnLayoutListener(mListener);
+ mListener = null;
+ }
+
super.onDetachedFromWindow();
}
@@ -4836,13 +4859,19 @@ public class WebView extends AbsoluteLayout
}
void setGLRectViewport() {
- View window = getRootView();
- int[] location = new int[2];
- getLocationInWindow(location);
- mGLRectViewport = new Rect(location[0], window.getHeight()
- - (location[1] + getHeight()),
- location[0] + getWidth(),
- window.getHeight() - location[1]);
+ // Use the getGlobalVisibleRect() to get the intersection among the parents
+ Rect webViewRect = new Rect();
+ boolean visible = getGlobalVisibleRect(webViewRect);
+
+ // Then need to invert the Y axis, just for GL
+ View rootView = getRootView();
+ int rootViewHeight = rootView.getHeight();
+ int savedWebViewBottom = webViewRect.bottom;
+ webViewRect.bottom = rootViewHeight - webViewRect.top;
+ webViewRect.top = rootViewHeight - savedWebViewBottom;
+
+ // Store the viewport
+ mGLRectViewport = webViewRect;
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1d3e4f4d9518..43434d369470 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7818,7 +7818,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int end = getSelectionEnd();
CharSequence selectedText = mTransformed.subSequence(start, end);
ClipData data = ClipData.newPlainText(null, null, selectedText);
- startDrag(data, getTextThumbnailBuilder(selectedText), false);
+ startDrag(data, getTextThumbnailBuilder(selectedText), false, null);
mDragSourcePositions = packRangeInLong(start, end);
stopSelectionActionMode();
} else {
@@ -8744,7 +8744,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Double tap detection
long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
- if (duration <= ViewConfiguration.getDoubleTapTimeout()) {
+ if (duration <= ViewConfiguration.getDoubleTapTimeout() &&
+ isPositionOnText(x, y)) {
final int deltaX = x - mPreviousTapPositionX;
final int deltaY = y - mPreviousTapPositionY;
final int distanceSquared = deltaX * deltaX + deltaY * deltaY;
diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
index c930c57c359f..bfef27571df8 100644
--- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java
+++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
@@ -27,6 +27,7 @@ import java.io.PrintStream;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.ThreadFactory;
import android.content.pm.PackageInfo;
import android.util.Log;
@@ -43,27 +44,40 @@ public class SamplingProfilerIntegration {
private static final boolean enabled;
private static final Executor snapshotWriter;
- private static final int samplingProfilerHz;
-
- /** Whether or not we've created the snapshots dir. */
- private static boolean dirMade = false;
+ private static final int samplingProfilerMilliseconds;
+ private static final int samplingProfilerDepth;
/** Whether or not a snapshot is being persisted. */
private static final AtomicBoolean pending = new AtomicBoolean(false);
static {
- samplingProfilerHz = SystemProperties.getInt("persist.sys.profiler_hz", 0);
- // Disabling this for now, as it crashes when enabled server-side. So adding
- // a new property ("REALLY") for those wanting to test and fix it.
- boolean really = SystemProperties.getInt("persist.sys.profiler_hz_REALLY", 0) > 0;
- if (samplingProfilerHz > 0 && really) {
- snapshotWriter = Executors.newSingleThreadExecutor();
- enabled = true;
- Log.i(TAG, "Profiler is enabled. Sampling Profiler Hz: " + samplingProfilerHz);
+ samplingProfilerMilliseconds = SystemProperties.getInt("persist.sys.profiler_ms", 0);
+ samplingProfilerDepth = SystemProperties.getInt("persist.sys.profiler_depth", 4);
+ if (samplingProfilerMilliseconds > 0) {
+ File dir = new File(SNAPSHOT_DIR);
+ dir.mkdirs();
+ // the directory needs to be writable to anybody to allow file writing
+ dir.setWritable(true, false);
+ // the directory needs to be executable to anybody to allow file creation
+ dir.setExecutable(true, false);
+ if (dir.isDirectory()) {
+ snapshotWriter = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ return new Thread(r, TAG);
+ }
+ });
+ enabled = true;
+ Log.i(TAG, "Profiling enabled. Sampling interval ms: "
+ + samplingProfilerMilliseconds);
+ } else {
+ snapshotWriter = null;
+ enabled = true;
+ Log.w(TAG, "Profiling setup failed. Could not create " + SNAPSHOT_DIR);
+ }
} else {
snapshotWriter = null;
enabled = false;
- Log.i(TAG, "Profiler is disabled.");
+ Log.i(TAG, "Profiling disabled.");
}
}
@@ -85,8 +99,8 @@ public class SamplingProfilerIntegration {
}
ThreadGroup group = Thread.currentThread().getThreadGroup();
SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupTheadSet(group);
- INSTANCE = new SamplingProfiler(4, threadSet); // TODO parameter for depth
- INSTANCE.start(1000/samplingProfilerHz);
+ INSTANCE = new SamplingProfiler(samplingProfilerDepth, threadSet);
+ INSTANCE.start(samplingProfilerMilliseconds);
}
/**
@@ -106,25 +120,8 @@ public class SamplingProfilerIntegration {
if (pending.compareAndSet(false, true)) {
snapshotWriter.execute(new Runnable() {
public void run() {
- if (!dirMade) {
- File dir = new File(SNAPSHOT_DIR);
- dir.mkdirs();
- // the directory needs to be writable to anybody
- dir.setWritable(true, false);
- // the directory needs to be executable to anybody
- // don't know why yet, but mode 723 would work, while
- // mode 722 throws FileNotFoundExecption at line 151
- dir.setExecutable(true, false);
- if (new File(SNAPSHOT_DIR).isDirectory()) {
- dirMade = true;
- } else {
- Log.w(TAG, "Creation of " + SNAPSHOT_DIR + " failed.");
- pending.set(false);
- return;
- }
- }
try {
- writeSnapshot(SNAPSHOT_DIR, processName, packageInfo);
+ writeSnapshotFile(processName, packageInfo);
} finally {
pending.set(false);
}
@@ -140,7 +137,7 @@ public class SamplingProfilerIntegration {
if (!enabled) {
return;
}
- writeSnapshot("zygote", null);
+ writeSnapshotFile("zygote", null);
INSTANCE.shutdown();
INSTANCE = null;
}
@@ -148,7 +145,7 @@ public class SamplingProfilerIntegration {
/**
* pass in PackageInfo to retrieve various values for snapshot header
*/
- private static void writeSnapshot(String dir, String processName, PackageInfo packageInfo) {
+ private static void writeSnapshotFile(String processName, PackageInfo packageInfo) {
if (!enabled) {
return;
}
@@ -161,7 +158,7 @@ public class SamplingProfilerIntegration {
*/
long start = System.currentTimeMillis();
String name = processName.replaceAll(":", ".");
- String path = dir + "/" + name + "-" +System.currentTimeMillis() + ".snapshot";
+ String path = SNAPSHOT_DIR + "/" + name + "-" +System.currentTimeMillis() + ".snapshot";
PrintStream out = null;
try {
out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path)));
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ddc63ddb8681..a2666e24f778 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1013,7 +1013,7 @@
<permission android:name="android.permission.SHUTDOWN"
android:label="@string/permlab_shutdown"
android:description="@string/permdesc_shutdown"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows an application to tell the activity manager to temporarily
stop application switches, putting it into a special mode that
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index cef057e30f7d..74167640187e 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,9 +52,8 @@ Android Market within a 14-day period ending on the data collection date noted b
<div class="dashboard-panel">
<img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:7.9,15.0,0.1,40.8,36.2&chl=
-Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
-6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:6.3,10.6,0.1,39.6,43.4&chl
+=Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,6fad0c" />
<table>
<tr>
@@ -62,13 +61,13 @@ Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
<th>API Level</th>
<th>Distribution</th>
</tr>
-<tr><td>Android 1.5</td><td>3</td><td>7.9%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>15.0%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>40.8%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>36.2%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>6.3%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>10.6%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>39.6%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>43.4%</td></tr>
</table>
-<p><em>Data collected during two weeks ending on November 1, 2010</em></p>
+<p><em>Data collected during two weeks ending on December 1, 2010</em></p>
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
</div><!-- end dashboard-panel -->
@@ -97,17 +96,16 @@ Android Market within a 14-day period ending on the date indicated on the x-axis
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
-chxl=0%3A%7C2010/05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/
-01%7C10/15%7C2010/11/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25
-%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:98.9,99.3,100.3,100.8,99.7,99.
-8,99.8,99.7,99.8,99.9,99.9,99.9,99.9|61.6,63.1,72.7,76.1,78.4,80.9,84.3,86.5,87.9,89.2,90.2,91.1,92.
-0|32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8,75.3,77.0|0.0,0.0,0.8,1.2,1.8,3.3,4.3,11.3,
-27.8,32.1,33.4,34.5,36.2&chm=tAndroid%201.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,
-5b831d,1,0,15,,t::-5|b,aadb5e,1,2,0|tAndroid%202.1,38540b,2,0,15,,t::-5|b,91da1e,2,3,0|tAndroid%202.
-2,131d02,3,7,15,,t::-5|B,6fad0c,3,4,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|
-Android%202.2&chco=add274,94d134,73ad18,507d08" />
-
-<p><em>Last historical dataset collected during two weeks ending on November 1, 2010</em></p>
+chxl=0:|2010/06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|10/01|10/15|11/01|11/15|2010/12/01|1:|0
+%25|25%25|50%25|75%25|100%25|2:|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&
+chxtc=0,5&chd=t:100.3,100.8,99.7,99.8,99.8,99.7,99.8,99.9,99.9,99.9,99.9,99.9,99.9|72.7,76.1,78.4,80
+.9,84.3,86.5,87.9,89.2,90.2,91.1,92.0,92.7,93.6|45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8,75.3,77
+.0,79.0,83.0|0.8,1.2,1.8,3.3,4.3,11.3,27.8,32.1,33.4,34.5,36.2,38.3,43.4&chm=tAndroid%201.5,7caa36,0
+,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,5b831d,1,0,15,,t::-5|b,aadb5e,1,2,0|tAndroid%202.1,38540b
+,2,0,15,,t::-5|b,91da1e,2,3,0|tAndroid%202.2,131d02,3,5,15,,t::-5|B,6fad0c,3,4,0&chg=7,25&chdl=
+Android%201.5|Android%201.6|Android%202.1|Android%202.2&chco=add274,94d134,73ad18,507d08" />
+
+<p><em>Last historical dataset collected during two weeks ending on December 1, 2010</em></p>
</div><!-- end dashboard-panel -->
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 078daa76d501..b0597c4e6ee4 100755
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.defcontainer">
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
+ <uses-permission android:name="android.permission.ACCESS_ALL_DOWNLOADS"/>
<uses-permission android:name="android.permission.ASEC_ACCESS"/>
<uses-permission android:name="android.permission.ASEC_CREATE"/>
<uses-permission android:name="android.permission.ASEC_DESTROY"/>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index d1e61a9052cf..4d0835fae12c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -169,7 +169,7 @@ public class ShirtPocket extends FrameLayout {
thumb = new DragThumbnailBuilder(mWindow.findViewById(R.id.preview));
}
- v.startDrag(clip, thumb, false);
+ v.startDrag(clip, thumb, false, null);
// TODO: only discard the clipping if it was accepted
stash(null);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 27ec1af5eda0..d7a6a0e4f400 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -619,7 +619,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mDragInProgress && newWin.isPotentialDragTarget()) {
DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED,
touchX - newWin.mFrame.left, touchY - newWin.mFrame.top,
- desc, null, false);
+ null, desc, null, false);
try {
newWin.mClient.dispatchDragEvent(event);
// track each window that we've notified that the drag is starting
@@ -659,7 +659,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.d(TAG, "broadcasting DRAG_ENDED");
}
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
- 0, 0, null, null, mDragResult);
+ 0, 0, null, null, null, mDragResult);
for (WindowState ws: mNotifiedWindows) {
try {
ws.mClient.dispatchDragEvent(evt);
@@ -711,7 +711,7 @@ public class WindowManagerService extends IWindowManager.Stub
// force DRAG_EXITED_EVENT if appropriate
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED,
x - mTargetWindow.mFrame.left, y - mTargetWindow.mFrame.top,
- null, null, false);
+ null, null, null, false);
mTargetWindow.mClient.dispatchDragEvent(evt);
if (myPid != mTargetWindow.mSession.mPid) {
evt.recycle();
@@ -723,7 +723,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION,
x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
- null, null, false);
+ null, null, null, false);
touchedWin.mClient.dispatchDragEvent(evt);
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
@@ -754,7 +754,7 @@ public class WindowManagerService extends IWindowManager.Stub
final IBinder token = touchedWin.mClient.asBinder();
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP,
x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
- null, mData, false);
+ null, null, mData, false);
try {
touchedWin.mClient.dispatchDragEvent(evt);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 2de1cbb0267b..ca87b4e868b8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -23,6 +23,7 @@ import com.android.layoutlib.api.IXmlPullParser;
import com.android.layoutlib.api.LayoutBridge;
import com.android.layoutlib.api.SceneParams;
import com.android.layoutlib.api.SceneResult;
+import com.android.layoutlib.api.SceneResult.SceneStatus;
import com.android.layoutlib.bridge.android.BridgeAssetManager;
import com.android.layoutlib.bridge.impl.FontLoader;
import com.android.layoutlib.bridge.impl.LayoutSceneImpl;
@@ -308,8 +309,13 @@ public final class Bridge extends LayoutBridge {
return new BridgeLayoutScene(scene, lastResult);
} catch (Throwable t) {
- t.printStackTrace();
- return new BridgeLayoutScene(null, new SceneResult("error!", t));
+ // get the real cause of the exception.
+ Throwable t2 = t;
+ while (t2.getCause() != null) {
+ t2 = t.getCause();
+ }
+ return new BridgeLayoutScene(null,
+ new SceneResult(SceneStatus.ERROR_UNKNOWN, t2.getMessage(), t2));
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
index 97bf857447fa..f80721436aac 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
@@ -16,12 +16,16 @@
package com.android.layoutlib.bridge;
+import com.android.layoutlib.api.IXmlPullParser;
import com.android.layoutlib.api.LayoutScene;
import com.android.layoutlib.api.SceneParams;
import com.android.layoutlib.api.SceneResult;
import com.android.layoutlib.api.ViewInfo;
import com.android.layoutlib.bridge.impl.LayoutSceneImpl;
+import android.view.View;
+import android.view.ViewGroup;
+
import java.awt.image.BufferedImage;
import java.util.Map;
@@ -92,13 +96,86 @@ public class BridgeLayoutScene extends LayoutScene {
}
@Override
- public void dispose() {
- // TODO Auto-generated method stub
+ public SceneResult insertChild(Object parentView, IXmlPullParser childXml, Object beforeSibling,
+ IAnimationListener listener) {
+ if (parentView instanceof ViewGroup == false) {
+ throw new IllegalArgumentException("parentView is not a ViewGroup");
+ }
+ if (beforeSibling != null && beforeSibling instanceof View == false) {
+ throw new IllegalArgumentException("beforeSibling is not a View");
+ }
+
+ try {
+ mScene.prepareThread();
+ mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
+ if (mLastResult == SceneResult.SUCCESS) {
+ mLastResult = mScene.insertChild((ViewGroup) parentView, childXml,
+ (View) beforeSibling, listener);
+ }
+ } finally {
+ mScene.release();
+ mScene.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+
+ @Override
+ public SceneResult moveChild(Object parentView, Object childView, Object beforeSibling,
+ IAnimationListener listener) {
+ if (parentView instanceof ViewGroup == false) {
+ throw new IllegalArgumentException("parentView is not a ViewGroup");
+ }
+ if (childView instanceof View == false) {
+ throw new IllegalArgumentException("childView is not a View");
+ }
+ if (beforeSibling != null && beforeSibling instanceof View == false) {
+ throw new IllegalArgumentException("beforeSibling is not a View");
+ }
+
+ try {
+ mScene.prepareThread();
+ mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
+ if (mLastResult == SceneResult.SUCCESS) {
+ mLastResult = mScene.moveChild((ViewGroup) parentView, (View) childView,
+ (View) beforeSibling, listener);
+ }
+ } finally {
+ mScene.release();
+ mScene.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+ @Override
+ public SceneResult removeChild(Object childView, IAnimationListener listener) {
+ if (childView instanceof View == false) {
+ throw new IllegalArgumentException("childView is not a View");
+ }
+
+ try {
+ mScene.prepareThread();
+ mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
+ if (mLastResult == SceneResult.SUCCESS) {
+ mLastResult = mScene.removeChild((View) childView, listener);
+ }
+ } finally {
+ mScene.release();
+ mScene.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+ @Override
+ public void dispose() {
}
/*package*/ BridgeLayoutScene(LayoutSceneImpl scene, SceneResult lastResult) {
mScene = scene;
+ mScene.setScene(this);
mLastResult = lastResult;
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
index c20bdfd6c906..d5766ab2fa74 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
@@ -105,7 +105,7 @@ public class AnimationThread extends Thread {
try {
bundle.mTarget.handleMessage(bundle.mMessage);
if (mScene.render() == SceneResult.SUCCESS) {
- mListener.onNewFrame(mScene.getImage());
+ mListener.onNewFrame(mScene.getScene());
}
} finally {
mScene.release();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
index 8a0776724f1b..05d207cc0077 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
@@ -24,13 +24,16 @@ import com.android.internal.util.XmlUtils;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
+import com.android.layoutlib.api.IXmlPullParser;
import com.android.layoutlib.api.LayoutBridge;
+import com.android.layoutlib.api.LayoutScene;
import com.android.layoutlib.api.SceneParams;
import com.android.layoutlib.api.SceneResult;
import com.android.layoutlib.api.ViewInfo;
import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
import com.android.layoutlib.api.LayoutScene.IAnimationListener;
import com.android.layoutlib.api.SceneParams.RenderingMode;
+import com.android.layoutlib.api.SceneResult.SceneStatus;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
@@ -53,6 +56,7 @@ import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.View.AttachInfo;
import android.view.View.MeasureSpec;
import android.widget.FrameLayout;
@@ -92,6 +96,7 @@ public class LayoutSceneImpl {
private final SceneParams mParams;
// scene state
+ private LayoutScene mScene;
private BridgeContext mContext;
private BridgeXmlBlockParser mBlockParser;
private BridgeInflater mInflater;
@@ -362,7 +367,7 @@ public class LayoutSceneImpl {
return SceneResult.SUCCESS;
} catch (PostInflateException e) {
- return new SceneResult("Error during post inflation process:\n" + e.getMessage());
+ return new SceneResult(SceneStatus.ERROR_INFLATION, e.getMessage(), e);
} catch (Throwable e) {
// get the real cause of the exception.
Throwable t = e;
@@ -373,7 +378,7 @@ public class LayoutSceneImpl {
// log it
mParams.getLogger().error(t);
- return new SceneResult("Unknown error during inflation.", t);
+ return new SceneResult(SceneStatus.ERROR_INFLATION, t.getMessage(), t);
}
}
@@ -391,7 +396,7 @@ public class LayoutSceneImpl {
try {
long current = System.currentTimeMillis();
if (mViewRoot == null) {
- return new SceneResult("Layout has not been inflated!");
+ return new SceneResult(SceneStatus.ERROR_NOT_INFLATED);
}
// measure the views
int w_spec, h_spec;
@@ -487,7 +492,7 @@ public class LayoutSceneImpl {
// log it
mParams.getLogger().error(t);
- return new SceneResult("Unknown error during rendering.", t);
+ return new SceneResult(SceneStatus.ERROR_UNKNOWN, t.getMessage(), t);
}
}
@@ -530,12 +535,74 @@ public class LayoutSceneImpl {
return SceneResult.SUCCESS;
}
} catch (Exception e) {
- e.printStackTrace();
- return new SceneResult("", e);
+ // get the real cause of the exception.
+ Throwable t = e;
+ while (t.getCause() != null) {
+ t = t.getCause();
+ }
+
+ return new SceneResult(SceneStatus.ERROR_UNKNOWN, t.getMessage(), t);
}
}
- return new SceneResult("Failed to find animation");
+ return new SceneResult(SceneStatus.ERROR_ANIM_NOT_FOUND);
+ }
+
+ public SceneResult insertChild(ViewGroup parentView, IXmlPullParser childXml,
+ View beforeSibling, IAnimationListener listener) {
+ checkLock();
+
+ int index = parentView.indexOfChild(beforeSibling);
+ if (beforeSibling != null && index == -1) {
+ throw new IllegalArgumentException("beforeSibling not in parentView");
+ }
+
+ // create a block parser for the XML
+ BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext,
+ false /* platformResourceFlag */);
+
+ // inflate the child without adding it to the root since we want to control where it'll
+ // get added. We do pass the parentView however to ensure that the layoutParams will
+ // be created correctly.
+ View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
+
+ // add it to the parentView in the correct location
+ parentView.addView(child, index);
+
+ return render();
+ }
+
+ public SceneResult moveChild(ViewGroup parentView, View childView, View beforeSibling,
+ IAnimationListener listener) {
+ checkLock();
+
+ int index = parentView.indexOfChild(beforeSibling);
+ if (beforeSibling != null && index == -1) {
+ throw new IllegalArgumentException("beforeSibling not in parentView");
+ }
+
+ ViewParent parent = childView.getParent();
+ if (parent instanceof ViewGroup) {
+ ViewGroup parentGroup = (ViewGroup) parent;
+ parentGroup.removeView(childView);
+ }
+
+ // add it to the parentView in the correct location
+ parentView.addView(childView, index);
+
+ return render();
+ }
+
+ public SceneResult removeChild(View childView, IAnimationListener listener) {
+ checkLock();
+
+ ViewParent parent = childView.getParent();
+ if (parent instanceof ViewGroup) {
+ ViewGroup parentGroup = (ViewGroup) parent;
+ parentGroup.removeView(childView);
+ }
+
+ return render();
}
/**
@@ -915,4 +982,12 @@ public class LayoutSceneImpl {
public Map<String, String> getDefaultViewPropertyValues(Object viewObject) {
return mContext.getDefaultPropMap(viewObject);
}
+
+ public void setScene(LayoutScene scene) {
+ mScene = scene;
+ }
+
+ public LayoutScene getScene() {
+ return mScene;
+ }
}