diff options
Diffstat (limited to 'core/java/android')
84 files changed, 2333 insertions, 646 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 10ef535..63c9fec 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2402,6 +2402,13 @@ public class Activity extends ContextThemeWrapper } return false; } + + /** + * Called when the main window associated with the activity has been dismissed. + */ + public void onWindowDismissed() { + finish(); + } /** * Called to process key events. You can override this to intercept all diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 7ca3459..c877cd3 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1289,106 +1289,15 @@ public class ActivityManager { } /** - * Information you can retrieve about the WindowManager StackBox hierarchy. - * @hide - */ - public static class StackBoxInfo implements Parcelable { - public int stackBoxId; - public float weight; - public boolean vertical; - public Rect bounds; - public StackBoxInfo[] children; - public int stackId; - public StackInfo stack; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(stackBoxId); - dest.writeFloat(weight); - dest.writeInt(vertical ? 1 : 0); - bounds.writeToParcel(dest, flags); - dest.writeInt(stackId); - if (children != null) { - children[0].writeToParcel(dest, flags); - children[1].writeToParcel(dest, flags); - } else { - stack.writeToParcel(dest, flags); - } - } - - public void readFromParcel(Parcel source) { - stackBoxId = source.readInt(); - weight = source.readFloat(); - vertical = source.readInt() == 1; - bounds = Rect.CREATOR.createFromParcel(source); - stackId = source.readInt(); - if (stackId == -1) { - children = new StackBoxInfo[2]; - children[0] = StackBoxInfo.CREATOR.createFromParcel(source); - children[1] = StackBoxInfo.CREATOR.createFromParcel(source); - } else { - stack = StackInfo.CREATOR.createFromParcel(source); - } - } - - public static final Creator<StackBoxInfo> CREATOR = - new Creator<ActivityManager.StackBoxInfo>() { - - @Override - public StackBoxInfo createFromParcel(Parcel source) { - return new StackBoxInfo(source); - } - - @Override - public StackBoxInfo[] newArray(int size) { - return new StackBoxInfo[size]; - } - }; - - public StackBoxInfo() { - } - - public StackBoxInfo(Parcel source) { - readFromParcel(source); - } - - public String toString(String prefix) { - StringBuilder sb = new StringBuilder(256); - sb.append(prefix); sb.append("Box id=" + stackBoxId); sb.append(" weight=" + weight); - sb.append(" vertical=" + vertical); sb.append(" bounds=" + bounds.toShortString()); - sb.append("\n"); - if (children != null) { - sb.append(prefix); sb.append("First child=\n"); - sb.append(children[0].toString(prefix + " ")); - sb.append(prefix); sb.append("Second child=\n"); - sb.append(children[1].toString(prefix + " ")); - } else { - sb.append(prefix); sb.append("Stack=\n"); - sb.append(stack.toString(prefix + " ")); - } - return sb.toString(); - } - - @Override - public String toString() { - return toString(""); - } - } - - /** * Information you can retrieve about an ActivityStack in the system. * @hide */ public static class StackInfo implements Parcelable { public int stackId; - public Rect bounds; + public Rect bounds = new Rect(); public int[] taskIds; public String[] taskNames; + public int displayId; @Override public int describeContents() { @@ -1404,6 +1313,7 @@ public class ActivityManager { dest.writeInt(bounds.bottom); dest.writeIntArray(taskIds); dest.writeStringArray(taskNames); + dest.writeInt(displayId); } public void readFromParcel(Parcel source) { @@ -1412,6 +1322,7 @@ public class ActivityManager { source.readInt(), source.readInt(), source.readInt(), source.readInt()); taskIds = source.createIntArray(); taskNames = source.createStringArray(); + displayId = source.readInt(); } public static final Creator<StackInfo> CREATOR = new Creator<StackInfo>() { @@ -1435,7 +1346,9 @@ public class ActivityManager { public String toString(String prefix) { StringBuilder sb = new StringBuilder(256); sb.append(prefix); sb.append("Stack id="); sb.append(stackId); - sb.append(" bounds="); sb.append(bounds.toShortString()); sb.append("\n"); + sb.append(" bounds="); sb.append(bounds.toShortString()); + sb.append(" displayId="); sb.append(displayId); + sb.append("\n"); prefix = prefix + " "; for (int i = 0; i < taskIds.length; ++i) { sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]); diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 74266cc..7695ecc 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -16,7 +16,7 @@ package android.app; -import android.app.ActivityManager.StackBoxInfo; +import android.app.ActivityManager.StackInfo; import android.content.ComponentName; import android.content.IIntentReceiver; import android.content.IIntentSender; @@ -31,6 +31,7 @@ import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Rect; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -611,18 +612,6 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case CREATE_STACK_TRANSACTION: { - data.enforceInterface(IActivityManager.descriptor); - int taskId = data.readInt(); - int relativeStackId = data.readInt(); - int position = data.readInt(); - float weight = data.readFloat(); - int res = createStack(taskId, relativeStackId, position, weight); - reply.writeNoException(); - reply.writeInt(res); - return true; - } - case MOVE_TASK_TO_STACK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int taskId = data.readInt(); @@ -635,25 +624,26 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case RESIZE_STACK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - int stackBoxId = data.readInt(); + int stackId = data.readInt(); float weight = data.readFloat(); - resizeStackBox(stackBoxId, weight); + Rect r = Rect.CREATOR.createFromParcel(data); + resizeStack(stackId, r); reply.writeNoException(); return true; } - case GET_STACK_BOXES_TRANSACTION: { + case GET_ALL_STACK_INFOS_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - List<StackBoxInfo> list = getStackBoxes(); + List<StackInfo> list = getAllStackInfos(); reply.writeNoException(); reply.writeTypedList(list); return true; } - case GET_STACK_BOX_INFO_TRANSACTION: { + case GET_STACK_INFO_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - int stackBoxId = data.readInt(); - StackBoxInfo info = getStackBoxInfo(stackBoxId); + int stackId = data.readInt(); + StackInfo info = getStackInfo(stackId); reply.writeNoException(); if (info != null) { reply.writeInt(1); @@ -2028,6 +2018,54 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case CREATE_ACTIVITY_CONTAINER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder parentActivityToken = data.readStrongBinder(); + IActivityContainerCallback callback = + (IActivityContainerCallback) data.readStrongBinder(); + IActivityContainer activityContainer = + createActivityContainer(parentActivityToken, callback); + reply.writeNoException(); + if (activityContainer != null) { + reply.writeInt(1); + reply.writeStrongBinder(activityContainer.asBinder()); + } else { + reply.writeInt(0); + } + return true; + } + + case DELETE_ACTIVITY_CONTAINER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IActivityContainer activityContainer = + IActivityContainer.Stub.asInterface(data.readStrongBinder()); + deleteActivityContainer(activityContainer); + reply.writeNoException(); + return true; + } + + case GET_ACTIVITY_CONTAINER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder activityToken = data.readStrongBinder(); + IActivityContainer activityContainer = getEnclosingActivityContainer(activityToken); + reply.writeNoException(); + if (activityContainer != null) { + reply.writeInt(1); + reply.writeStrongBinder(activityContainer.asBinder()); + } else { + reply.writeInt(0); + } + return true; + } + + case GET_HOME_ACTIVITY_TOKEN_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder homeActivityToken = getHomeActivityToken(); + reply.writeNoException(); + reply.writeStrongBinder(homeActivityToken); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -2715,24 +2753,6 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } @Override - public int createStack(int taskId, int relativeStackBoxId, int position, float weight) - throws RemoteException - { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IActivityManager.descriptor); - data.writeInt(taskId); - data.writeInt(relativeStackBoxId); - data.writeInt(position); - data.writeFloat(weight); - mRemote.transact(CREATE_STACK_TRANSACTION, data, reply, 0); - reply.readException(); - int res = reply.readInt(); - data.recycle(); - reply.recycle(); - return res; - } - @Override public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException { Parcel data = Parcel.obtain(); @@ -2747,44 +2767,44 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } @Override - public void resizeStackBox(int stackBoxId, float weight) throws RemoteException + public void resizeStack(int stackBoxId, Rect r) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(stackBoxId); - data.writeFloat(weight); + r.writeToParcel(data, 0); mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY); reply.readException(); data.recycle(); reply.recycle(); } @Override - public List<StackBoxInfo> getStackBoxes() throws RemoteException + public List<StackInfo> getAllStackInfos() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - mRemote.transact(GET_STACK_BOXES_TRANSACTION, data, reply, 0); + mRemote.transact(GET_ALL_STACK_INFOS_TRANSACTION, data, reply, 0); reply.readException(); - ArrayList<StackBoxInfo> list = reply.createTypedArrayList(StackBoxInfo.CREATOR); + ArrayList<StackInfo> list = reply.createTypedArrayList(StackInfo.CREATOR); data.recycle(); reply.recycle(); return list; } @Override - public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException + public StackInfo getStackInfo(int stackId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - data.writeInt(stackBoxId); - mRemote.transact(GET_STACK_BOX_INFO_TRANSACTION, data, reply, 0); + data.writeInt(stackId); + mRemote.transact(GET_STACK_INFO_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); - StackBoxInfo info = null; + StackInfo info = null; if (res != 0) { - info = StackBoxInfo.CREATOR.createFromParcel(reply); + info = StackInfo.CREATOR.createFromParcel(reply); } data.recycle(); reply.recycle(); @@ -4660,5 +4680,70 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + public IActivityContainer createActivityContainer(IBinder parentActivityToken, + IActivityContainerCallback callback) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(parentActivityToken); + data.writeStrongBinder((IBinder)callback); + mRemote.transact(CREATE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0); + reply.readException(); + final int result = reply.readInt(); + final IActivityContainer res; + if (result == 1) { + res = IActivityContainer.Stub.asInterface(reply.readStrongBinder()); + } else { + res = null; + } + data.recycle(); + reply.recycle(); + return res; + } + + public void deleteActivityContainer(IActivityContainer activityContainer) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(activityContainer.asBinder()); + mRemote.transact(DELETE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + + public IActivityContainer getEnclosingActivityContainer(IBinder activityToken) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(activityToken); + mRemote.transact(GET_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0); + reply.readException(); + final int result = reply.readInt(); + final IActivityContainer res; + if (result == 1) { + res = IActivityContainer.Stub.asInterface(reply.readStrongBinder()); + } else { + res = null; + } + data.recycle(); + reply.recycle(); + return res; + } + + public IBinder getHomeActivityToken() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(GET_HOME_ACTIVITY_TOKEN_TRANSACTION, data, reply, 0); + reply.readException(); + IBinder res = reply.readStrongBinder(); + data.recycle(); + reply.recycle(); + return res; + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9243095..614b064 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2227,15 +2227,27 @@ public final class ActivityThread { ContextImpl appContext = new ContextImpl(); appContext.init(r.packageInfo, r.token, this); appContext.setOuterContext(activity); + Context baseContext = appContext; + + final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); + try { + IActivityContainer container = + ActivityManagerNative.getDefault().getEnclosingActivityContainer(r.token); + final int displayId = + container == null ? Display.DEFAULT_DISPLAY : container.getDisplayId(); + if (displayId > Display.DEFAULT_DISPLAY) { + Display display = dm.getRealDisplay(displayId, r.token); + baseContext = appContext.createDisplayContext(display); + } + } catch (RemoteException e) { + } // For debugging purposes, if the activity's package name contains the value of // the "debug.use-second-display" system property as a substring, then show // its content on a secondary display if there is one. - Context baseContext = appContext; String pkgName = SystemProperties.get("debug.second-display.pkg"); if (pkgName != null && !pkgName.isEmpty() && r.packageInfo.mPackageName.contains(pkgName)) { - DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); for (int displayId : dm.getDisplayIds()) { if (displayId != Display.DEFAULT_DISPLAY) { Display display = dm.getRealDisplay(displayId, r.token); diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java new file mode 100644 index 0000000..113f123 --- /dev/null +++ b/core/java/android/app/ActivityView.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2013 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.app; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.IIntentSender; +import android.content.Intent; +import android.content.IntentSender; +import android.graphics.SurfaceTexture; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.MotionEvent; +import android.view.Surface; +import android.view.TextureView; +import android.view.TextureView.SurfaceTextureListener; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +/** @hide */ +public class ActivityView extends ViewGroup { + private final String TAG = "ActivityView"; + private final boolean DEBUG = false; + + private final TextureView mTextureView; + private IActivityContainer mActivityContainer; + private Activity mActivity; + private int mWidth; + private int mHeight; + private Surface mSurface; + + // Only one IIntentSender or Intent may be queued at a time. Most recent one wins. + IIntentSender mQueuedPendingIntent; + Intent mQueuedIntent; + + public ActivityView(Context context) { + this(context, null); + } + + public ActivityView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ActivityView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + while (context instanceof ContextWrapper) { + if (context instanceof Activity) { + mActivity = (Activity)context; + break; + } + context = ((ContextWrapper)context).getBaseContext(); + } + if (mActivity == null) { + throw new IllegalStateException("The ActivityView's Context is not an Activity."); + } + + mTextureView = new TextureView(context); + mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); + addView(mTextureView); + if (DEBUG) Log.v(TAG, "ctor()"); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + mTextureView.layout(0, 0, r - l, b - t); + } + + @Override + protected void onAttachedToWindow() { + if (DEBUG) Log.v(TAG, "onAttachedToWindow()"); + super.onAttachedToWindow(); + try { + final IBinder token = mActivity.getActivityToken(); + mActivityContainer = + ActivityManagerNative.getDefault().createActivityContainer(token, null); + } catch (RemoteException e) { + throw new IllegalStateException("ActivityView: Unable to create ActivityContainer. " + + e); + } + + attachToSurfaceWhenReady(); + } + + @Override + protected void onDetachedFromWindow() { + if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer); + super.onDetachedFromWindow(); + if (mActivityContainer != null) { + detach(); + try { + ActivityManagerNative.getDefault().deleteActivityContainer(mActivityContainer); + } catch (RemoteException e) { + } + mActivityContainer = null; + } + } + + @Override + protected void onWindowVisibilityChanged(int visibility) { + if (DEBUG) Log.v(TAG, "onWindowVisibilityChanged(): visibility=" + visibility); + super.onWindowVisibilityChanged(visibility); + switch (visibility) { + case View.VISIBLE: + attachToSurfaceWhenReady(); + break; + case View.INVISIBLE: + break; + case View.GONE: + break; + } + } + + private boolean injectInputEvent(InputEvent event) { + try { + return mActivityContainer != null && mActivityContainer.injectEvent(event); + } catch (RemoteException e) { + return false; + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return injectInputEvent(event) || super.onTouchEvent(event); + } + + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { + if (injectInputEvent(event)) { + return true; + } + } + return super.onGenericMotionEvent(event); + } + + public boolean isAttachedToDisplay() { + return mSurface != null; + } + + public void startActivity(Intent intent) { + if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " + + (isAttachedToDisplay() ? "" : "not") + " attached"); + if (mSurface != null) { + try { + mActivityContainer.startActivity(intent); + } catch (RemoteException e) { + throw new IllegalStateException("ActivityView: Unable to startActivity. " + e); + } + } else { + mQueuedIntent = intent; + mQueuedPendingIntent = null; + } + } + + private void startActivityIntentSender(IIntentSender iIntentSender) { + try { + mActivityContainer.startActivityIntentSender(iIntentSender); + } catch (RemoteException e) { + throw new IllegalStateException( + "ActivityView: Unable to startActivity from IntentSender. " + e); + } + } + + public void startActivity(IntentSender intentSender) { + if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " + + (isAttachedToDisplay() ? "" : "not") + " attached"); + final IIntentSender iIntentSender = intentSender.getTarget(); + if (mSurface != null) { + startActivityIntentSender(iIntentSender); + } else { + mQueuedPendingIntent = iIntentSender; + mQueuedIntent = null; + } + } + + public void startActivity(PendingIntent pendingIntent) { + if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " " + + (isAttachedToDisplay() ? "" : "not") + " attached"); + final IIntentSender iIntentSender = pendingIntent.getTarget(); + if (mSurface != null) { + startActivityIntentSender(iIntentSender); + } else { + mQueuedPendingIntent = iIntentSender; + mQueuedIntent = null; + } + } + + private void attachToSurfaceWhenReady() { + final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); + if (mActivityContainer == null || surfaceTexture == null || mSurface != null) { + // Either not ready to attach, or already attached. + return; + } + + WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics metrics = new DisplayMetrics(); + wm.getDefaultDisplay().getMetrics(metrics); + + mSurface = new Surface(surfaceTexture); + try { + mActivityContainer.attachToSurface(mSurface, mWidth, mHeight, metrics.densityDpi); + } catch (RemoteException e) { + mSurface.release(); + mSurface = null; + throw new IllegalStateException( + "ActivityView: Unable to create ActivityContainer. " + e); + } + + if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null || + mQueuedPendingIntent != null ? "" : "no") + " queued intent"); + if (mQueuedIntent != null) { + startActivity(mQueuedIntent); + mQueuedIntent = null; + } else if (mQueuedPendingIntent != null) { + startActivityIntentSender(mQueuedPendingIntent); + mQueuedPendingIntent = null; + } + } + + private void detach() { + if (DEBUG) Log.d(TAG, "detach: attached=" + isAttachedToDisplay()); + if (mSurface != null) { + try { + mActivityContainer.detachFromDisplay(); + } catch (RemoteException e) { + } + mSurface.release(); + mSurface = null; + } + } + + private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener { + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, + int height) { + if (DEBUG) Log.d(TAG, "onSurfaceTextureAvailable: width=" + width + " height=" + + height); + mWidth = width; + mHeight = height; + if (mActivityContainer != null) { + attachToSurfaceWhenReady(); + } + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, + int height) { + if (DEBUG) Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height); + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { + if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed"); + detach(); + return true; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { +// Log.d(TAG, "onSurfaceTextureUpdated"); + } + + } +} diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index cda2c5f..a8277b5 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -695,6 +695,10 @@ public class Dialog implements DialogInterface, Window.Callback, public void onDetachedFromWindow() { } + + public void onWindowDismissed() { + dismiss(); + } /** * Called to process key events. You can override this to intercept all diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index d626e5f..af8f177 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -1402,6 +1402,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mRestored = false; mBackStackNesting = 0; mFragmentManager = null; + mChildFragmentManager = null; mActivity = null; mFragmentId = 0; mContainerId = 0; diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index bf2a629..76f9d97 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1026,6 +1026,7 @@ final class FragmentManagerImpl extends FragmentManager { f.mActivity = null; f.mParentFragment = null; f.mFragmentManager = null; + f.mChildFragmentManager = null; } } } diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl new file mode 100644 index 0000000..5b80e06 --- /dev/null +++ b/core/java/android/app/IActivityContainer.aidl @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2013, 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.app; + +import android.app.IActivityContainerCallback; +import android.content.Intent; +import android.content.IIntentSender; +import android.os.IBinder; +import android.view.InputEvent; +import android.view.Surface; + +/** @hide */ +interface IActivityContainer { + void attachToDisplay(int displayId); + void attachToSurface(in Surface surface, int width, int height, int density); + void detachFromDisplay(); + int startActivity(in Intent intent); + int startActivityIntentSender(in IIntentSender intentSender); + int getDisplayId(); + boolean injectEvent(in InputEvent event); +} diff --git a/core/java/android/app/IActivityContainerCallback.aidl b/core/java/android/app/IActivityContainerCallback.aidl new file mode 100644 index 0000000..55c2001 --- /dev/null +++ b/core/java/android/app/IActivityContainerCallback.aidl @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2013, 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.app; + +import android.os.IBinder; + +/** @hide */ +interface IActivityContainerCallback { + oneway void onLastActivityRemoved(IBinder container); +} diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 77c2ea0..02a6343 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -18,7 +18,7 @@ package android.app; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningServiceInfo; -import android.app.ActivityManager.StackBoxInfo; +import android.app.ActivityManager.StackInfo; import android.content.ComponentName; import android.content.ContentProviderNative; import android.content.IContentProvider; @@ -36,6 +36,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.os.Debug; @@ -117,12 +118,10 @@ public interface IActivityManager extends IInterface { public void moveTaskToBack(int task) throws RemoteException; public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException; public void moveTaskBackwards(int task) throws RemoteException; - public int createStack(int taskId, int relativeStackBoxId, int position, float weight) - throws RemoteException; public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException; - public void resizeStackBox(int stackBoxId, float weight) throws RemoteException; - public List<StackBoxInfo> getStackBoxes() throws RemoteException; - public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException; + public void resizeStack(int stackId, Rect bounds) throws RemoteException; + public List<StackInfo> getAllStackInfos() throws RemoteException; + public StackInfo getStackInfo(int stackId) throws RemoteException; public void setFocusedStack(int stackId) throws RemoteException; public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException; /* oneway */ @@ -408,6 +407,18 @@ public interface IActivityManager extends IInterface { public void performIdleMaintenance() throws RemoteException; + /** @hide */ + public IActivityContainer createActivityContainer(IBinder parentActivityToken, + IActivityContainerCallback callback) throws RemoteException; + + /** @hide */ + public void deleteActivityContainer(IActivityContainer container) throws RemoteException; + + public IActivityContainer getEnclosingActivityContainer(IBinder activityToken) + throws RemoteException; + + public IBinder getHomeActivityToken() throws RemoteException; + /* * Private non-Binder interfaces */ @@ -678,12 +689,12 @@ public interface IActivityManager extends IInterface { int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164; int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165; int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166; - int CREATE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167; + int CREATE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167; int MOVE_TASK_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+168; int RESIZE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+169; - int GET_STACK_BOXES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170; + int GET_ALL_STACK_INFOS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170; int SET_FOCUSED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+171; - int GET_STACK_BOX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172; + int GET_STACK_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172; int CONVERT_FROM_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+173; int CONVERT_TO_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174; int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175; @@ -694,4 +705,7 @@ public interface IActivityManager extends IInterface { int RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+180; int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181; int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182; + int GET_HOME_ACTIVITY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183; + int GET_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184; + int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185; } diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 3efd3c0..181eb63 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -71,4 +71,14 @@ interface IWallpaperManager { * Returns the desired minimum height for the wallpaper. */ int getHeightHint(); + + /** + * Returns the name of the wallpaper. Private API. + */ + String getName(); + + /** + * Informs the service that wallpaper settings have been restored. Private API. + */ + void settingsRestored(); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index c63e586..6be2b7b 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -348,6 +348,13 @@ public class Notification implements Parcelable */ public static final int FLAG_HIGH_PRIORITY = 0x00000080; + /** + * Bit to be bitswise-ored into the {@link #flags} field that should be + * set if this notification is relevant to the current device only + * and it is not recommended that it bridge to other devices. + */ + public static final int FLAG_LOCAL_ONLY = 0x00000100; + public int flags; /** @@ -1532,6 +1539,17 @@ public class Notification implements Parcelable } /** + * Set whether or not this notification should not bridge to other devices. + * + * <p>Some notifications can be bridged to other devices for remote display. + * This hint can be set to recommend this notification not be bridged. + */ + public Builder setLocalOnly(boolean localOnly) { + setFlag(FLAG_LOCAL_ONLY, localOnly); + return this; + } + + /** * Set which notification properties will be inherited from system defaults. * <p> * The value should be one or more of the following fields combined with @@ -1568,12 +1586,31 @@ public class Notification implements Parcelable } /** - * Add metadata to this notification. + * Merge additional metadata into this notification. + * + * <p>Values within the Bundle will replace existing extras values in this Builder. * - * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's + * @see Notification#extras + */ + public Builder addExtras(Bundle bag) { + if (mExtras == null) { + mExtras = new Bundle(bag); + } else { + mExtras.putAll(bag); + } + return this; + } + + /** + * Set metadata for this notification. + * + * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's * current contents are copied into the Notification each time {@link #build()} is * called. * + * <p>Replaces any existing extras values with those from the provided Bundle. + * Use {@link #addExtras} to merge in metadata instead. + * * @see Notification#extras */ public Builder setExtras(Bundle bag) { @@ -1582,6 +1619,23 @@ public class Notification implements Parcelable } /** + * Get the current metadata Bundle used by this notification Builder. + * + * <p>The returned Bundle is shared with this Builder. + * + * <p>The current contents of this Bundle are copied into the Notification each time + * {@link #build()} is called. + * + * @see Notification#extras + */ + public Bundle getExtras() { + if (mExtras == null) { + mExtras = new Bundle(); + } + return mExtras; + } + + /** * Add an action to this notification. Actions are typically displayed by * the system as a button adjacent to the notification content. * <p> @@ -1778,7 +1832,7 @@ public class Notification implements Parcelable RemoteViews button = new RemoteViews(mContext.getPackageName(), tombstone ? R.layout.notification_action_tombstone : R.layout.notification_action); - button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0); + button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0); button.setTextViewText(R.id.action0, action.title); if (!tombstone) { button.setOnClickPendingIntent(R.id.action0, action.actionIntent); @@ -1839,7 +1893,7 @@ public class Notification implements Parcelable * this Notification object. * @hide */ - public void addExtras(Bundle extras) { + public void populateExtras(Bundle extras) { // Store original information used in the construction of this object extras.putCharSequence(EXTRA_TITLE, mContentTitle); extras.putCharSequence(EXTRA_TEXT, mContentText); @@ -1877,7 +1931,7 @@ public class Notification implements Parcelable n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle(); - addExtras(n.extras); + populateExtras(n.extras); if (mStyle != null) { mStyle.addExtras(n.extras); } @@ -1900,8 +1954,7 @@ public class Notification implements Parcelable * An object that can apply a rich notification style to a {@link Notification.Builder} * object. */ - public static abstract class Style - { + public static abstract class Style { private CharSequence mBigContentTitle; private CharSequence mSummaryText = null; private boolean mSummaryTextSet = false; diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index bdd0adb..45467b8 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -87,23 +87,25 @@ public final class PendingIntent implements Parcelable { private final IIntentSender mTarget; /** - * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and - * {@link #getService}: this - * PendingIntent can only be used once. If set, after + * Flag indicating that this PendingIntent can be used only once. + * For use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}. <p>If set, after * {@link #send()} is called on it, it will be automatically * canceled for you and any future attempt to send through it will fail. */ public static final int FLAG_ONE_SHOT = 1<<30; /** - * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and - * {@link #getService}: if the described PendingIntent does not already - * exist, then simply return null instead of creating it. + * Flag indicating that if the described PendingIntent already + * exists, then simply return null instead of creating it. + * For use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}. */ public static final int FLAG_NO_CREATE = 1<<29; /** - * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and - * {@link #getService}: if the described PendingIntent already exists, - * the current one is canceled before generating a new one. You can use + * Flag indicating that if the described PendingIntent already exists, + * the current one should be canceled before generating a new one. + * For use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}. <p>You can use * this to retrieve a new PendingIntent when you are only changing the * extra data in the Intent; by canceling the previous pending intent, * this ensures that only entities given the new data will be able to @@ -112,10 +114,10 @@ public final class PendingIntent implements Parcelable { */ public static final int FLAG_CANCEL_CURRENT = 1<<28; /** - * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and - * {@link #getService}: if the described PendingIntent already exists, - * then keep it but its replace its extra data with what is in this new - * Intent. This can be used if you are creating intents where only the + * Flag indicating that if the described PendingIntent already exists, + * then keep it but replace its extra data with what is in this new + * Intent. For use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}. <p>This can be used if you are creating intents where only the * extras change, and don't care that any entities that received your * previous PendingIntent will be able to launch it with your new * extras even if they are not explicitly given to it. @@ -203,7 +205,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} * you supply here should almost always be an <em>explicit intent</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the activity. @@ -234,7 +236,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} * you supply here should almost always be an <em>explicit intent</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the activity. @@ -326,7 +328,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} objects * you supply here should almost always be <em>explicit intents</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the activity. @@ -376,7 +378,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} objects * you supply here should almost always be <em>explicit intents</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the activity. @@ -446,7 +448,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} * you supply here should almost always be an <em>explicit intent</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should perform * the broadcast. @@ -500,7 +502,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} * you supply here should almost always be an <em>explicit intent</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the service. diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl index bb4f5f1..12ee3b6 100644 --- a/core/java/android/app/backup/IBackupManager.aidl +++ b/core/java/android/app/backup/IBackupManager.aidl @@ -43,14 +43,14 @@ interface IBackupManager { void dataChanged(String packageName); /** - * Erase all backed-up data for the given package from the storage + * Erase all backed-up data for the given package from the given storage * destination. * * Any application can invoke this method for its own package, but * only callers who hold the android.permission.BACKUP permission * may invoke it for arbitrary packages. */ - void clearBackupData(String packageName); + void clearBackupData(String transportName, String packageName); /** * Notifies the Backup Manager Service that an agent has become available. This diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index e2bc80a..d1f1f2a 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -27,14 +27,14 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Pair; + import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.HashMap; -import java.util.LinkedList; +import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Random; @@ -183,6 +183,43 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; /** + * Activity Action: Show a system activity to request BLE advertising.<br> + * If the device is not doing BLE advertising, this activity will start BLE advertising for the + * device, otherwise it will continue BLE advertising using the current + * {@link BluetoothAdvScanData}. <br> + * Note this activity will also request the user to turn on Bluetooth if it's not currently + * enabled. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_START_ADVERTISING = + "android.bluetooth.adapter.action.START_ADVERTISING"; + + /** + * Activity Action: Stop the current BLE advertising. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_STOP_ADVERTISING = + "android.bluetooth.adapter.action.STOP_ADVERTISING"; + + /** + * Broadcast Action: Indicate BLE Advertising is started. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = + "android.bluetooth.adapter.action.ADVERTISING_STARTED"; + + /** + * Broadcast Action: Indicated BLE Advertising is stopped. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = + "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; + + /** * Activity Action: Show a system activity that allows the user to turn on * Bluetooth. * <p>This system activity will return once Bluetooth has completed turning @@ -251,7 +288,6 @@ public final class BluetoothAdapter { */ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; - /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. @@ -365,6 +401,8 @@ public final class BluetoothAdapter { private IBluetooth mService; private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; + private BluetoothAdvScanData mBluetoothAdvScanData = null; + private GattCallbackWrapper mAdvertisingCallback; /** * Get a handle to the default local Bluetooth adapter. @@ -438,6 +476,97 @@ public final class BluetoothAdapter { } /** + * Returns a {@link BluetoothAdvScanData} object representing advertising data. + * @hide + */ + public BluetoothAdvScanData getAdvScanData() { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + Log.e(TAG, "failed to start, iGatt null"); + return null; + } + if (mBluetoothAdvScanData == null) { + mBluetoothAdvScanData = new BluetoothAdvScanData(iGatt, BluetoothAdvScanData.AD); + } + return mBluetoothAdvScanData; + } catch (RemoteException e) { + Log.e(TAG, "failed to get advScanData, error: " + e); + return null; + } + } + + + /** + * Start BLE advertising using current {@link BluetoothAdvScanData}. + * An app should start advertising by requesting + * {@link BluetoothAdapter#ACTION_START_ADVERTISING} instead of calling this method directly. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * + * @return true if BLE avertising succeeds, false otherwise. + * @hide + */ + public boolean startAdvertising() { + if (getState() != STATE_ON) return false; + + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported. + return false; + } + // Restart/reset advertising packets if advertising is in progress. + if (isAdvertising()) { + // Invalid advertising callback. + if (mAdvertisingCallback == null || mAdvertisingCallback.mLeHandle == -1) { + Log.e(TAG, "failed to restart advertising, invalid callback"); + return false; + } + iGatt.startAdvertising(mAdvertisingCallback.mLeHandle); + return true; + } + UUID uuid = UUID.randomUUID(); + GattCallbackWrapper wrapper = + new GattCallbackWrapper(this, null, null, GattCallbackWrapper.CALLBACK_TYPE_ADV); + iGatt.registerClient(new ParcelUuid(uuid), wrapper); + mAdvertisingCallback = wrapper; + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** + * Stop BLE advertising. + * An app should stop advertising by requesting + * {@link BluetoothAdapter#ACTION_STOP_ADVERTISING} instead of calling this method directly. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * @return true if BLE advertising stops, false otherwise. + * @hide + */ + public boolean stopAdvertisting() { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + return false; + } + if (mAdvertisingCallback == null) { + // no callback. + return false; + } + mAdvertisingCallback.stopAdvertising(); + mAdvertisingCallback = null; + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** * Return true if Bluetooth is currently enabled and ready for use. * <p>Equivalent to: * <code>getBluetoothState() == STATE_ON</code> @@ -849,6 +978,23 @@ public final class BluetoothAdapter { } /** + * Returns whether BLE is currently advertising. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. + * + * @hide + */ + public boolean isAdvertising() { + if (getState() != STATE_ON) return false; + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + return iGatt.isAdvertising(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + return false; + } + + /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. * <p>If Bluetooth state is not {@link #STATE_ON}, this API @@ -1546,8 +1692,12 @@ public final class BluetoothAdapter { private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { private static final int LE_CALLBACK_REG_TIMEOUT = 2000; private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; + private static final int CALLBACK_TYPE_SCAN = 0; + private static final int CALLBACK_TYPE_ADV = 1; private final LeScanCallback mLeScanCb; + private int mCallbackType; + // mLeHandle 0: not registered // -1: scan stopped // >0: registered and scan started @@ -1561,6 +1711,16 @@ public final class BluetoothAdapter { mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; + mCallbackType = CALLBACK_TYPE_SCAN; + } + + public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, + UUID[] uuid, int type) { + mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter); + mLeScanCb = leScanCb; + mScanFilter = uuid; + mLeHandle = 0; + mCallbackType = type; } public boolean scanStarted() { @@ -1583,6 +1743,30 @@ public final class BluetoothAdapter { return started; } + public void stopAdvertising() { + synchronized (this) { + if (mLeHandle <= 0) { + Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); + return; + } + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + iGatt.stopAdvertising(); + Log.d(TAG, "unregeistering client " + mLeHandle); + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "Failed to stop advertising and unregister" + e); + } + } else { + Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); + } + mLeHandle = -1; + notifyAll(); + } + } + public void stopLeScan() { synchronized(this) { if (mLeHandle <= 0) { @@ -1624,14 +1808,18 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mScanFilter == null) { - iGatt.startScan(mLeHandle, false); + if (mCallbackType == CALLBACK_TYPE_ADV) { + iGatt.startAdvertising(mLeHandle); } else { - ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(mScanFilter[i]); - } - iGatt.startScanWithUuids(mLeHandle, false, uuids); + if (mScanFilter == null) { + iGatt.startScan(mLeHandle, false); + } else { + ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(mScanFilter[i]); + } + iGatt.startScanWithUuids(mLeHandle, false, uuids); + } } } else { Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); @@ -1642,7 +1830,7 @@ public final class BluetoothAdapter { mLeHandle = -1; } if (mLeHandle == -1) { - // registration succeeded but start scan failed + // registration succeeded but start scan or advertise failed if (iGatt != null) { try { iGatt.unregisterClient(mLeHandle); diff --git a/core/java/android/bluetooth/BluetoothAdvScanData.java b/core/java/android/bluetooth/BluetoothAdvScanData.java new file mode 100644 index 0000000..a97b0a8 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAdvScanData.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2013 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; +import android.os.ParcelUuid; +import android.os.RemoteException; +import android.util.Log; + +import java.util.Collections; +import java.util.List; + + +/** + * This class provides the public APIs to set advertising and scan response data when BLE device + * operates in peripheral mode. <br> + * The exact format is defined in Bluetooth 4.0 specification, Volume 3, Part C, Section 11 + * @hide + */ +public final class BluetoothAdvScanData { + + /** + * Available data types of {@link BluetoothAdvScanData}. + */ + public static final int AD = 0; // Advertising Data + public static final int SCAN_RESPONSE = 1; // Scan Response + public static final int EIR = 2; // Extended Inquiry Response + + private static final String TAG = "BluetoothAdvScanData"; + + /** + * Data type of BluetoothAdvScanData. + */ + private final int mDataType; + /** + * Bluetooth Gatt Service. + */ + private IBluetoothGatt mBluetoothGatt; + + /** + * @param mBluetoothGatt + * @param dataType + */ + public BluetoothAdvScanData(IBluetoothGatt mBluetoothGatt, int dataType) { + this.mBluetoothGatt = mBluetoothGatt; + this.mDataType = dataType; + } + + /** + * @return advertising data type. + */ + public int getDataType() { + return mDataType; + } + + /** + * Set manufactureCode and manufactureData. + * Returns true if manufacturer data is set, false if there is no enough room to set + * manufacturer data or the data is already set. + * @param manufacturerCode - unique identifier for the manufacturer + * @param manufacturerData - data associated with the specific manufacturer. + */ + public boolean setManufacturerData(int manufacturerCode, byte[] manufacturerData) { + if (mDataType != AD) return false; + try { + return mBluetoothGatt.setAdvManufacturerCodeAndData(manufacturerCode, manufacturerData); + } catch (RemoteException e) { + return false; + } + } + + /** + * Set service data. Note the service data can only be set when the data type is {@code AD}; + * @param serviceData + */ + public boolean setServiceData(byte[] serviceData) { + + if (mDataType != AD) return false; + if (serviceData == null) return false; + try { + return mBluetoothGatt.setAdvServiceData(serviceData); + } catch (RemoteException e) { + return false; + } + } + + /** + * Returns an immutable list of service uuids that will be advertised. + */ + public List<ParcelUuid> getServiceUuids() { + try { + return Collections.unmodifiableList(mBluetoothGatt.getAdvServiceUuids()); + } catch (RemoteException e) { + return null; + } + } + + /** + * Returns manufacturer data. + */ + public byte[] getManufacturerData() { + if (mBluetoothGatt == null) return null; + try { + return mBluetoothGatt.getAdvManufacturerData(); + } catch (RemoteException e) { + return null; + } + } + + /** + * Returns service data. + */ + public byte[] getServiceData() { + if (mBluetoothGatt == null) return null; + try { + return mBluetoothGatt.getAdvServiceData(); + } catch (RemoteException e) { + return null; + } + } + + /** + * Remove manufacturer data based on given manufacturer code. + * @param manufacturerCode + */ + public void removeManufacturerCodeAndData(int manufacturerCode) { + if (mBluetoothGatt != null) { + try { + mBluetoothGatt.removeAdvManufacturerCodeAndData(manufacturerCode); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } + } +} diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index a2bb78c..cd093c5 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -553,14 +553,6 @@ public final class BluetoothGatt implements BluetoothProfile { Log.w(TAG, "Unhandled exception in callback", ex); } } - - /** - * Listen command status callback - * @hide - */ - public void onListen(int status) { - if (DBG) Log.d(TAG, "onListen() - status=" + status); - } }; /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) { @@ -693,71 +685,6 @@ public final class BluetoothGatt implements BluetoothProfile { return true; } - /** - * Starts or stops sending of advertisement packages to listen for connection - * requests from a central devices. - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param start Start or stop advertising - */ - /*package*/ void listen(boolean start) { - if (mContext == null || !mContext.getResources(). - getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) { - throw new UnsupportedOperationException("BluetoothGatt#listen is blocked"); - } - if (DBG) Log.d(TAG, "listen() - start: " + start); - if (mService == null || mClientIf == 0) return; - - try { - mService.clientListen(mClientIf, start); - } catch (RemoteException e) { - Log.e(TAG,"",e); - } - } - - /** - * Sets the advertising data contained in the adv. response packet. - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param advData true to set adv. data, false to set scan response - * @param includeName Inlucde the name in the adv. response - * @param includeTxPower Include TX power value - * @param minInterval Minimum desired scan interval (optional) - * @param maxInterval Maximum desired scan interval (optional) - * @param appearance The appearance flags for the device (optional) - * @param manufacturerData Manufacturer specific data including company ID (optional) - */ - /*package*/ void setAdvData(boolean advData, boolean includeName, boolean includeTxPower, - Integer minInterval, Integer maxInterval, - Integer appearance, Byte[] manufacturerData) { - if (mContext == null || !mContext.getResources(). - getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) { - throw new UnsupportedOperationException("BluetoothGatt#setAdvData is blocked"); - } - if (DBG) Log.d(TAG, "setAdvData()"); - if (mService == null || mClientIf == 0) return; - - byte[] data = new byte[0]; - if (manufacturerData != null) { - data = new byte[manufacturerData.length]; - for(int i = 0; i != manufacturerData.length; ++i) { - data[i] = manufacturerData[i]; - } - } - - try { - mService.setAdvData(mClientIf, !advData, - includeName, includeTxPower, - minInterval != null ? minInterval : 0, - maxInterval != null ? maxInterval : 0, - appearance != null ? appearance : 0, data); - } catch (RemoteException e) { - Log.e(TAG,"",e); - } - } - /** * Disconnects an established connection, or cancels a connection attempt * currently in progress. diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java index 58ee54f..153215c 100644 --- a/core/java/android/bluetooth/BluetoothGattServer.java +++ b/core/java/android/bluetooth/BluetoothGattServer.java @@ -537,7 +537,7 @@ public final class BluetoothGattServer implements BluetoothProfile { try { mService.beginServiceDeclaration(mServerIf, service.getType(), service.getInstanceId(), service.getHandles(), - new ParcelUuid(service.getUuid())); + new ParcelUuid(service.getUuid()), service.isAdvertisePreferred()); List<BluetoothGattService> includedServices = service.getIncludedServices(); for (BluetoothGattService includedService : includedServices) { diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java index 1e66369..52bc0f7 100644 --- a/core/java/android/bluetooth/BluetoothGattService.java +++ b/core/java/android/bluetooth/BluetoothGattService.java @@ -15,8 +15,6 @@ */ package android.bluetooth; -import android.bluetooth.BluetoothDevice; - import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -82,6 +80,11 @@ public class BluetoothGattService { protected List<BluetoothGattService> mIncludedServices; /** + * Whether the service uuid should be advertised. + */ + private boolean mAdvertisePreferred; + + /** * Create a new BluetoothGattService. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * @@ -263,4 +266,20 @@ public class BluetoothGattService { } return null; } + + /** + * Returns whether the uuid of the service should be advertised. + * @hide + */ + public boolean isAdvertisePreferred() { + return mAdvertisePreferred; + } + + /** + * Set whether the service uuid should be advertised. + * @hide + */ + public void setAdvertisePreferred(boolean advertisePreferred) { + this.mAdvertisePreferred = advertisePreferred; + } } diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java index 844f432..33232ed 100644 --- a/core/java/android/bluetooth/BluetoothInputDevice.java +++ b/core/java/android/bluetooth/BluetoothInputDevice.java @@ -76,6 +76,12 @@ public final class BluetoothInputDevice implements BluetoothProfile { public static final String ACTION_PROTOCOL_MODE_CHANGED = "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED"; + /** + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_REPORT = + "android.bluetooth.input.profile.action.REPORT"; /** * @hide @@ -130,17 +136,17 @@ public final class BluetoothInputDevice implements BluetoothProfile { /** * @hide */ - public static final byte REPORT_TYPE_INPUT = 0; + public static final byte REPORT_TYPE_INPUT = 1; /** * @hide */ - public static final byte REPORT_TYPE_OUTPUT = 1; + public static final byte REPORT_TYPE_OUTPUT = 2; /** * @hide */ - public static final byte REPORT_TYPE_FEATURE = 2; + public static final byte REPORT_TYPE_FEATURE = 3; /** * @hide diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index d10eaea..1e75fc2 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -417,27 +417,28 @@ public final class BluetoothSocket implements Closeable { * if an i/o error occurs. */ /*package*/ void flush() throws IOException { + if (mSocketOS == null) throw new IOException("flush is called on null OutputStream"); if (VDBG) Log.d(TAG, "flush: " + mSocketOS); mSocketOS.flush(); } /*package*/ int read(byte[] b, int offset, int length) throws IOException { - - if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); - int ret = mSocketIS.read(b, offset, length); - if(ret < 0) - throw new IOException("bt socket closed, read return: " + ret); - if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); - return ret; + if (mSocketIS == null) throw new IOException("read is called on null InputStream"); + if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); + int ret = mSocketIS.read(b, offset, length); + if(ret < 0) + throw new IOException("bt socket closed, read return: " + ret); + if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); + return ret; } /*package*/ int write(byte[] b, int offset, int length) throws IOException { - - if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); - mSocketOS.write(b, offset, length); - // There is no good way to confirm since the entire process is asynchronous anyway - if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length); - return length; + if (mSocketOS == null) throw new IOException("write is called on null OutputStream"); + if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); + mSocketOS.write(b, offset, length); + // There is no good way to confirm since the entire process is asynchronous anyway + if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length); + return length; } @Override diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index abdf949..4b28516 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -73,6 +73,9 @@ public final class BluetoothUuid { public static final ParcelUuid MAS = ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB"); + public static final ParcelUuid BASE_UUID = + ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB"); + public static final ParcelUuid[] RESERVED_UUIDS = { AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget, @@ -211,4 +214,17 @@ public final class BluetoothUuid { long value = (uuid.getMostSignificantBits() & 0x0000FFFF00000000L) >>> 32; return (int)value; } + + /** + * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid. + * @param parcelUuid + * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise. + */ + public static boolean isShortUuid(ParcelUuid parcelUuid) { + UUID uuid = parcelUuid.getUuid(); + if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) { + return false; + } + return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L); + } } diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index df393db..784cdcc 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -37,10 +37,15 @@ interface IBluetoothGatt { void unregisterClient(in int clientIf); void clientConnect(in int clientIf, in String address, in boolean isDirect); void clientDisconnect(in int clientIf, in String address); - void clientListen(in int clientIf, in boolean start); - void setAdvData(in int clientIf, in boolean setScanRsp, in boolean inclName, - in boolean inclTxPower, in int minInterval, in int maxInterval, - in int appearance, in byte[] manufacturerData); + void startAdvertising(in int appIf); + void stopAdvertising(); + boolean setAdvServiceData(in byte[] serviceData); + byte[] getAdvServiceData(); + boolean setAdvManufacturerCodeAndData(int manufactureCode, in byte[] manufacturerData); + byte[] getAdvManufacturerData(); + List<ParcelUuid> getAdvServiceUuids(); + void removeAdvManufacturerCodeAndData(int manufacturerCode); + boolean isAdvertising(); void refreshDevice(in int clientIf, in String address); void discoverServices(in int clientIf, in String address); void readCharacteristic(in int clientIf, in String address, in int srvcType, @@ -75,7 +80,7 @@ interface IBluetoothGatt { void serverDisconnect(in int serverIf, in String address); void beginServiceDeclaration(in int serverIf, in int srvcType, in int srvcInstanceId, in int minHandles, - in ParcelUuid srvcId); + in ParcelUuid srvcId, boolean advertisePreferred); void addIncludedService(in int serverIf, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId); void addCharacteristic(in int serverIf, in ParcelUuid charId, diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl index 60c297b..e3563fc 100644 --- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl @@ -63,5 +63,4 @@ interface IBluetoothGattCallback { in int charInstId, in ParcelUuid charUuid, in byte[] value); void onReadRemoteRssi(in String address, in int rssi, in int status); - void onListen(in int status); } diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html index 200a21b..d9ca4f1 100644 --- a/core/java/android/bluetooth/package.html +++ b/core/java/android/bluetooth/package.html @@ -8,17 +8,19 @@ The Bluetooth API supports both "Classic Bluetooth" and Bluetooth Low Energy.</p <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> guide. For more information about Bluetooth Low Energy, see the <a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html"> -Bluetooth Low Energy</a> guide.</p> +Bluetooth Low Energy</a> (BLE) guide.</p> {@more} <p>The Bluetooth APIs let applications:</p> <ul> - <li>Scan for other Bluetooth devices (including Bluetooth Low Energy - devices)</li> - <li>Query the local Bluetooth adapter for paired Bluetooth devices</li> - <li>Establish RFCOMM channels/sockets</li> - <li>Connect to specified sockets on other devices</li> - <li>Transfer data to and from other devices</li> + <li>Scan for other Bluetooth devices (including BLE devices).</li> + <li>Query the local Bluetooth adapter for paired Bluetooth devices.</li> + <li>Establish RFCOMM channels/sockets.</li> + <li>Connect to specified sockets on other devices.</li> + <li>Transfer data to and from other devices.</li> + <li>Communicate with BLE devices, such as proximity sensors, heart rate + monitors, fitness devices, and so on.</li> + <li>Act as a GATT client or a GATT server (BLE).</li> </ul> <p> diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java index 5cb6e77..be35f08 100644 --- a/core/java/android/content/ClipDescription.java +++ b/core/java/android/content/ClipDescription.java @@ -87,7 +87,7 @@ public class ClipDescription implements Parcelable { /** * Helper to compare two MIME types, where one may be a pattern. * @param concreteType A fully-specified MIME type. - * @param desiredType A desired MIME type that may be a pattern such as *\/*. + * @param desiredType A desired MIME type that may be a pattern such as */*. * @return Returns true if the two MIME types match. */ public static boolean compareMimeTypes(String concreteType, String desiredType) { diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index ddde3fb..9d0ab3a 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -1328,7 +1328,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param uri The data in the content provider being queried. * @param mimeTypeFilter The type of data the client desires. May be - * a pattern, such as *\/* to retrieve all possible data types. + * a pattern, such as */* to retrieve all possible data types. * @return Returns {@code null} if there are no possible data streams for the * given mimeTypeFilter. Otherwise returns an array of all available * concrete MIME types. @@ -1366,7 +1366,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param uri The data in the content provider being queried. * @param mimeTypeFilter The type of data the client desires. May be - * a pattern, such as *\/*, if the caller does not have specific type + * a pattern, such as */*, if the caller does not have specific type * requirements; in this case the content provider will pick its best * type matching the pattern. * @param opts Additional options from the client. The definitions of @@ -1427,7 +1427,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param uri The data in the content provider being queried. * @param mimeTypeFilter The type of data the client desires. May be - * a pattern, such as *\/*, if the caller does not have specific type + * a pattern, such as */*, if the caller does not have specific type * requirements; in this case the content provider will pick its best * type matching the pattern. * @param opts Additional options from the client. The definitions of diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 4e6cc92..2bf4d7d 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -344,7 +344,7 @@ public abstract class ContentResolver { * @param url A Uri identifying content (either a list or specific type), * using the content:// scheme. * @param mimeTypeFilter The desired MIME type. This may be a pattern, - * such as *\/*, to query for all available MIME types that match the + * such as */*, to query for all available MIME types that match the * pattern. * @return Returns an array of MIME type strings for all available * data streams that match the given mimeTypeFilter. If there are none, @@ -815,7 +815,7 @@ public abstract class ContentResolver { * * <p>Note that if this function is called for read-only input (mode is "r") * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} - * for you with a MIME type of "*\/*". This allows such callers to benefit + * for you with a MIME type of "*/*". This allows such callers to benefit * from any built-in data conversion that a provider implements. * * @param uri The desired URI to open. @@ -868,7 +868,7 @@ public abstract class ContentResolver { * * <p>Note that if this function is called for read-only input (mode is "r") * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} - * for you with a MIME type of "*\/*". This allows such callers to benefit + * for you with a MIME type of "*/*". This allows such callers to benefit * from any built-in data conversion that a provider implements. * * @param uri The desired URI to open. @@ -993,7 +993,7 @@ public abstract class ContentResolver { * * @param uri The desired URI to open. * @param mimeType The desired MIME type of the returned data. This can - * be a pattern such as *\/*, which will allow the content provider to + * be a pattern such as */*, which will allow the content provider to * select a type, though there is no way for you to determine what type * it is returning. * @param opts Additional provider-dependent options. @@ -1026,7 +1026,7 @@ public abstract class ContentResolver { * * @param uri The desired URI to open. * @param mimeType The desired MIME type of the returned data. This can - * be a pattern such as *\/*, which will allow the content provider to + * be a pattern such as */*, which will allow the content provider to * select a type, though there is no way for you to determine what type * it is returning. * @param opts Additional provider-dependent options. @@ -1535,7 +1535,7 @@ public abstract class ContentResolver { * for a whole class of content. * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code> * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI - * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values + * specified by <em>uri</em> will cause notifications to be sent. If <code>true</code>, any URI values * at or below the specified URI will also trigger a match. * @param observer The object that receives callbacks when changes occur. * @see #unregisterContentObserver diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 2e2d4b8..9495283 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -844,7 +844,7 @@ public class Intent implements Parcelable, Cloneable { * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, then these flags will also be * set in the returned chooser intent, with its ClipData set appropriately: * either a direct reflection of {@link #getClipData()} if that is non-null, - * or a new ClipData build from {@link #getData()}. + * or a new ClipData built from {@link #getData()}. * * @param target The Intent that the user will be selecting an activity * to perform. @@ -3547,6 +3547,11 @@ public class Intent implements Parcelable, Cloneable { * it will be finished so that the user does not return to them, but * instead returns to whatever activity preceeded it. * + * <p>When this flag is assigned to the root activity all activities up + * to, but not including the root activity, will be cleared. This prevents + * this flag from being used to finish all activities in a task and thereby + * ending the task. + * * <p>This is useful for cases where you have a logical break in your * application. For example, an e-mail application may have a command * to view an attachment, which launches an image view activity to @@ -4424,7 +4429,7 @@ public class Intent implements Parcelable, Cloneable { * Return the {@link ClipData} associated with this Intent. If there is * none, returns null. See {@link #setClipData} for more information. * - * @see #setClipData; + * @see #setClipData */ public ClipData getClipData() { return mClipData; @@ -5440,7 +5445,7 @@ public class Intent implements Parcelable, Cloneable { * directly used by Intent. Applications should generally rely on the * MIME type of the Intent itself, not what it may find in the ClipData. * A common practice is to construct a ClipData for use with an Intent - * with a MIME type of "*\/*". + * with a MIME type of "*/*". * * @param clip The new clip to set. May be null to clear the current clip. */ @@ -7162,8 +7167,8 @@ public class Intent implements Parcelable, Cloneable { * * @param type MIME data type to normalize * @return normalized MIME data type, or null if the input was null - * @see {@link #setType} - * @see {@link #setTypeAndNormalize} + * @see #setType + * @see #setTypeAndNormalize */ public static String normalizeMimeType(String type) { if (type == null) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index c97c2b8..ddf0ed6 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1249,6 +1249,29 @@ public abstract class PackageManager { public static final String FEATURE_TELEVISION = "android.hardware.type.television"; /** + * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: This is a device dedicated to showing UI + * on a watch. A watch here is defined to be a device worn on the body, perhaps on + * the wrist. The user is very close when interacting with the device. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_WATCH = "android.hardware.type.watch"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports printing. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_PRINTING = "android.software.print"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device can perform backup and restore operations on installed applications. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_BACKUP = "android.software.backup"; + + /** * Action to external storage service to clean out removed apps. * @hide */ diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 60ccc61..433d5d1 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -738,14 +738,16 @@ public final class SQLiteDatabase extends SQLiteClosable { File dir = file.getParentFile(); if (dir != null) { final String prefix = file.getName() + "-mj"; - final FileFilter filter = new FileFilter() { + File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File candidate) { return candidate.getName().startsWith(prefix); } - }; - for (File masterJournal : dir.listFiles(filter)) { - deleted |= masterJournal.delete(); + }); + if (files != null) { + for (File masterJournal : files) { + deleted |= masterJournal.delete(); + } } } return deleted; diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index b931313..8c23129 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -1056,8 +1056,8 @@ public abstract class SensorManager { * is mapped. * * @param outR - * the transformed rotation matrix. inR and outR can be the same - * array, but it is not recommended for performance reason. + * the transformed rotation matrix. inR and outR should not be the same + * array. * * @return <code>true</code> on success. <code>false</code> if the input * parameters are incorrect, for instance if X and Y define the same diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index d5208d9..a517bc5 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -115,6 +115,7 @@ public final class DisplayManager { * </p> * * @see #createVirtualDisplay + * @see #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY */ public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0; @@ -171,6 +172,22 @@ public final class DisplayManager { */ public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2; + /** + * Virtual display flag: Only show this display's own content; do not mirror + * the content of another display. + * + * <p> + * This flag is used in conjunction with {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}. + * Ordinarily public virtual displays will automatically mirror the content of the + * default display if they have no windows of their own. When this flag is + * specified, the virtual display will only ever show its own content and + * will be blanked instead if it has no windows. + * </p> + * + * @see #createVirtualDisplay + */ + public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3; + /** @hide */ public DisplayManager(Context context) { mContext = context; @@ -297,16 +314,31 @@ public final class DisplayManager { } /** - * Initiates a fresh scan of availble Wifi displays. + * Starts scanning for available Wifi displays. * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. * <p> + * Calls to this method nest and must be matched by an equal number of calls to + * {@link #stopWifiDisplayScan()}. + * </p><p> + * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. + * </p> + * + * @hide + */ + public void startWifiDisplayScan() { + mGlobal.startWifiDisplayScan(); + } + + /** + * Stops scanning for available Wifi displays. + * <p> * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. * </p> * * @hide */ - public void scanWifiDisplays() { - mGlobal.scanWifiDisplays(); + public void stopWifiDisplayScan() { + mGlobal.stopWifiDisplayScan(); } /** @@ -414,8 +446,8 @@ public final class DisplayManager { * @param surface The surface to which the content of the virtual display should * be rendered, must be non-null. * @param flags A combination of virtual display flags: - * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION} - * or {@link #VIRTUAL_DISPLAY_FLAG_SECURE}. + * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION}, + * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, or {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}. * @return The newly created virtual display, or null if the application could * not create the virtual display. * diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 936a086..3417430 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -72,6 +72,8 @@ public final class DisplayManagerGlobal { private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>(); private int[] mDisplayIdCache; + private int mWifiDisplayScanNestCount; + private DisplayManagerGlobal(IDisplayManager dm) { mDm = dm; } @@ -267,11 +269,32 @@ public final class DisplayManagerGlobal { } } - public void scanWifiDisplays() { - try { - mDm.scanWifiDisplays(); - } catch (RemoteException ex) { - Log.e(TAG, "Failed to scan for Wifi displays.", ex); + public void startWifiDisplayScan() { + synchronized (mLock) { + if (mWifiDisplayScanNestCount++ == 0) { + registerCallbackIfNeededLocked(); + try { + mDm.startWifiDisplayScan(); + } catch (RemoteException ex) { + Log.e(TAG, "Failed to scan for Wifi displays.", ex); + } + } + } + } + + public void stopWifiDisplayScan() { + synchronized (mLock) { + if (--mWifiDisplayScanNestCount == 0) { + try { + mDm.stopWifiDisplayScan(); + } catch (RemoteException ex) { + Log.e(TAG, "Failed to scan for Wifi displays.", ex); + } + } else if (mWifiDisplayScanNestCount < 0) { + Log.wtf(TAG, "Wifi display scan nest count became negative: " + + mWifiDisplayScanNestCount); + mWifiDisplayScanNestCount = 0; + } } } diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java new file mode 100644 index 0000000..8430973 --- /dev/null +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 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.hardware.display; + +import android.view.DisplayInfo; + +/** + * Display manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class DisplayManagerInternal { + /** + * Called by the power manager to blank all displays. + */ + public abstract void blankAllDisplaysFromPowerManager(); + + /** + * Called by the power manager to unblank all displays. + */ + public abstract void unblankAllDisplaysFromPowerManager(); + + /** + * Returns information about the specified logical display. + * + * @param displayId The logical display id. + * @return The logical display info, or null if the display does not exist. The + * returned object must be treated as immutable. + */ + public abstract DisplayInfo getDisplayInfo(int displayId); + + /** + * Registers a display transaction listener to provide the client a chance to + * update its surfaces within the same transaction as any display layout updates. + * + * @param listener The listener to register. + */ + public abstract void registerDisplayTransactionListener(DisplayTransactionListener listener); + + /** + * Unregisters a display transaction listener to provide the client a chance to + * update its surfaces within the same transaction as any display layout updates. + * + * @param listener The listener to unregister. + */ + public abstract void unregisterDisplayTransactionListener(DisplayTransactionListener listener); + + /** + * Overrides the display information of a particular logical display. + * This is used by the window manager to control the size and characteristics + * of the default display. It is expected to apply the requested change + * to the display information synchronously so that applications will immediately + * observe the new state. + * + * NOTE: This method must be the only entry point by which the window manager + * influences the logical configuration of displays. + * + * @param displayId The logical display id. + * @param info The new data to be stored. + */ + public abstract void setDisplayInfoOverrideFromWindowManager( + int displayId, DisplayInfo info); + + /** + * Called by the window manager to perform traversals while holding a + * surface flinger transaction. + */ + public abstract void performTraversalInTransactionFromWindowManager(); + + /** + * Tells the display manager whether there is interesting unique content on the + * specified logical display. This is used to control automatic mirroring. + * <p> + * If the display has unique content, then the display manager arranges for it + * to be presented on a physical display if appropriate. Otherwise, the display manager + * may choose to make the physical display mirror some other logical display. + * </p> + * + * @param displayId The logical display id to update. + * @param hasContent True if the logical display has content. + * @param inTraversal True if called from WindowManagerService during a window traversal + * prior to call to performTraversalInTransactionFromWindowManager. + */ + public abstract void setDisplayHasContent(int displayId, boolean hasContent, + boolean inTraversal); + + /** + * Called within a Surface transaction whenever the size or orientation of a + * display may have changed. Provides an opportunity for the client to + * update the position of its surfaces as part of the same transaction. + */ + public interface DisplayTransactionListener { + void onDisplayTransaction(); + } +} diff --git a/core/java/android/hardware/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java new file mode 100644 index 0000000..c2d498b --- /dev/null +++ b/core/java/android/hardware/display/DisplayViewport.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012 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.hardware.display; + +import android.graphics.Rect; + +/** + * Describes how the pixels of physical display device reflects the content of + * a logical display. + * <p> + * This information is used by the input system to translate touch input from + * physical display coordinates into logical display coordinates. + * </p> + * + * @hide Only for use within the system server. + */ +public final class DisplayViewport { + // True if this viewport is valid. + public boolean valid; + + // The logical display id. + public int displayId; + + // The rotation applied to the physical coordinate system. + public int orientation; + + // The portion of the logical display that are presented on this physical display. + public final Rect logicalFrame = new Rect(); + + // The portion of the (rotated) physical display that shows the logical display contents. + // The relation between logical and physical frame defines how the coordinate system + // should be scaled or translated after rotation. + public final Rect physicalFrame = new Rect(); + + // The full width and height of the display device, rotated in the same + // manner as physicalFrame. This expresses the full native size of the display device. + // The physical frame should usually fit within this area. + public int deviceWidth; + public int deviceHeight; + + public void copyFrom(DisplayViewport viewport) { + valid = viewport.valid; + displayId = viewport.displayId; + orientation = viewport.orientation; + logicalFrame.set(viewport.logicalFrame); + physicalFrame.set(viewport.physicalFrame); + deviceWidth = viewport.deviceWidth; + deviceHeight = viewport.deviceHeight; + } + + // For debugging purposes. + @Override + public String toString() { + return "DisplayViewport{valid=" + valid + + ", displayId=" + displayId + + ", orientation=" + orientation + + ", logicalFrame=" + logicalFrame + + ", physicalFrame=" + physicalFrame + + ", deviceWidth=" + deviceWidth + + ", deviceHeight=" + deviceHeight + + "}"; + } +} diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 6b2c887..68eb13f 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -29,11 +29,14 @@ interface IDisplayManager { void registerCallback(in IDisplayManagerCallback callback); - // No permissions required. - void scanWifiDisplays(); + // Requires CONFIGURE_WIFI_DISPLAY permission. + // The process must have previously registered a callback. + void startWifiDisplayScan(); - // Requires CONFIGURE_WIFI_DISPLAY permission to connect to an unknown device. - // No permissions required to connect to a known device. + // Requires CONFIGURE_WIFI_DISPLAY permission. + void stopWifiDisplayScan(); + + // Requires CONFIGURE_WIFI_DISPLAY permission. void connectWifiDisplay(String address); // No permissions required. @@ -45,6 +48,12 @@ interface IDisplayManager { // Requires CONFIGURE_WIFI_DISPLAY permission. void forgetWifiDisplay(String address); + // Requires CONFIGURE_WIFI_DISPLAY permission. + void pauseWifiDisplay(); + + // Requires CONFIGURE_WIFI_DISPLAY permission. + void resumeWifiDisplay(); + // No permissions required. WifiDisplayStatus getWifiDisplayStatus(); @@ -55,10 +64,4 @@ interface IDisplayManager { // No permissions required but must be same Uid as the creator. void releaseVirtualDisplay(in IBinder token); - - // Requires CONFIGURE_WIFI_DISPLAY permission. - void pauseWifiDisplay(); - - // Requires CONFIGURE_WIFI_DISPLAY permission. - void resumeWifiDisplay(); } diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java new file mode 100644 index 0000000..8be94d0 --- /dev/null +++ b/core/java/android/hardware/input/InputManagerInternal.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 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.hardware.input; + +import android.hardware.display.DisplayViewport; +import android.view.InputEvent; + +/** + * Input manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class InputManagerInternal { + /** + * Sets information about the displays as needed by the input system. + * The input system should copy this information if required. + */ + public abstract void setDisplayViewports(DisplayViewport defaultViewport, + DisplayViewport externalTouchViewport); + + public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode); +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index c78a973..9ae4fa2 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -361,11 +361,17 @@ public class ConnectivityManager { */ public static final int TYPE_MOBILE_IA = 14; + /** + * The network that uses proxy to achieve connectivity. + * {@hide} + */ + public static final int TYPE_PROXY = 16; + /** {@hide} */ - public static final int MAX_RADIO_TYPE = TYPE_MOBILE_IA; + public static final int MAX_RADIO_TYPE = TYPE_PROXY; /** {@hide} */ - public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_IA; + public static final int MAX_NETWORK_TYPE = TYPE_PROXY; /** * If you want to set the default network preference,you can directly @@ -444,6 +450,8 @@ public class ConnectivityManager { return "WIFI_P2P"; case TYPE_MOBILE_IA: return "MOBILE_IA"; + case TYPE_PROXY: + return "PROXY"; default: return Integer.toString(type); } diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java new file mode 100644 index 0000000..461e8b8 --- /dev/null +++ b/core/java/android/net/ProxyDataTracker.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2014 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.net; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A data tracker responsible for bringing up and tearing down the system proxy server. + * + * {@hide} + */ +public class ProxyDataTracker extends BaseNetworkStateTracker { + private static final String TAG = "ProxyDataTracker"; + private static final String NETWORK_TYPE = "PROXY"; + + // TODO: investigate how to get these DNS addresses from the system. + private static final String DNS1 = "8.8.8.8"; + private static final String DNS2 = "8.8.4.4"; + private static final String REASON_ENABLED = "enabled"; + private static final String REASON_DISABLED = "disabled"; + private static final String REASON_PROXY_DOWN = "proxy_down"; + + private static final int MSG_TEAR_DOWN_REQUEST = 1; + private static final int MSG_SETUP_REQUEST = 2; + + private static final String PERMISSION_PROXY_STATUS_SENDER = + "android.permission.ACCESS_NETWORK_CONDITIONS"; + private static final String ACTION_PROXY_STATUS_CHANGE = + "com.android.net.PROXY_STATUS_CHANGE"; + private static final String KEY_IS_PROXY_AVAILABLE = "is_proxy_available"; + private static final String KEY_REPLY_TO_MESSENGER_BINDER = "reply_to_messenger_binder"; + private static final String KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE = + "reply_to_messenger_binder_bundle"; + + private Handler mTarget; + private Messenger mProxyStatusService; + private AtomicBoolean mReconnectRequested = new AtomicBoolean(false); + private AtomicBoolean mIsProxyAvailable = new AtomicBoolean(false); + private final AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); + + private final BroadcastReceiver mProxyStatusServiceListener = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ACTION_PROXY_STATUS_CHANGE)) { + mIsProxyAvailable.set(intent.getBooleanExtra(KEY_IS_PROXY_AVAILABLE, false)); + if (mIsProxyAvailable.get()) { + Bundle bundle = intent.getBundleExtra(KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE); + if (bundle == null || bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER) == null) { + Log.e(TAG, "no messenger binder in the intent to send future requests"); + mIsProxyAvailable.set(false); + return; + } + mProxyStatusService = + new Messenger(bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER)); + // If there is a pending reconnect request, do it now. + if (mReconnectRequested.get()) { + reconnect(); + } + } else { + setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, + REASON_PROXY_DOWN, null); + } + } else { + Log.d(TAG, "Unrecognized broadcast intent"); + } + } + }; + + /** + * Create a new ProxyDataTracker + */ + public ProxyDataTracker() { + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, ""); + mLinkProperties = new LinkProperties(); + mLinkCapabilities = new LinkCapabilities(); + mNetworkInfo.setIsAvailable(true); + try { + mLinkProperties.addDns(InetAddress.getByName(DNS1)); + mLinkProperties.addDns(InetAddress.getByName(DNS2)); + } catch (UnknownHostException e) { + Log.e(TAG, "Could not add DNS address", e); + } + } + + public Object Clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + @Override + public void startMonitoring(Context context, Handler target) { + mContext = context; + mTarget = target; + mContext.registerReceiver(mProxyStatusServiceListener, + new IntentFilter(ACTION_PROXY_STATUS_CHANGE), + PERMISSION_PROXY_STATUS_SENDER, + null); + } + + /** + * Disable connectivity to the network. + */ + public boolean teardown() { + setTeardownRequested(true); + mReconnectRequested.set(false); + try { + if (mIsProxyAvailable.get() && mProxyStatusService != null) { + mProxyStatusService.send(Message.obtain(null, MSG_TEAR_DOWN_REQUEST)); + } + } catch (RemoteException e) { + Log.e(TAG, "Unable to connect to proxy status service", e); + return false; + } + setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_DISABLED, null); + return true; + } + + /** + * Re-enable proxy data connectivity after a {@link #teardown()}. + */ + public boolean reconnect() { + mReconnectRequested.set(true); + setTeardownRequested(false); + if (!mIsProxyAvailable.get()) { + Log.w(TAG, "Reconnect requested even though proxy service is not up. Bailing."); + return false; + } + setDetailedState(NetworkInfo.DetailedState.CONNECTING, REASON_ENABLED, null); + + try { + mProxyStatusService.send(Message.obtain(null, MSG_SETUP_REQUEST)); + } catch (RemoteException e) { + Log.e(TAG, "Unable to connect to proxy status service", e); + setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_PROXY_DOWN, null); + return false; + } + // We'll assume proxy is set up successfully. If not, a status change broadcast will be + // received afterwards to indicate any failure. + setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null); + return true; + } + + /** + * Fetch default gateway address for the network + */ + public int getDefaultGatewayAddr() { + return mDefaultGatewayAddr.get(); + } + + /** + * Return the system properties name associated with the tcp buffer sizes + * for this network. + */ + public String getTcpBufferSizesPropName() { + return "net.tcp.buffersize.wifi"; + } + + /** + * Record the detailed state of a network, and if it is a + * change from the previous state, send a notification to + * any listeners. + * @param state the new @{code DetailedState} + * @param reason a {@code String} indicating a reason for the state change, + * if one was supplied. May be {@code null}. + * @param extraInfo optional {@code String} providing extra information about the state change + */ + private void setDetailedState(NetworkInfo.DetailedState state, String reason, + String extraInfo) { + mNetworkInfo.setDetailedState(state, reason, extraInfo); + Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); + msg.sendToTarget(); + } +} diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java index d4a3006..26e09b6 100644 --- a/core/java/android/os/AsyncTask.java +++ b/core/java/android/os/AsyncTask.java @@ -610,7 +610,7 @@ public abstract class AsyncTask<Params, Progress, Result> { * still running. Each call to this method will trigger the execution of * {@link #onProgressUpdate} on the UI thread. * - * {@link #onProgressUpdate} will note be called if the task has been + * {@link #onProgressUpdate} will not be called if the task has been * canceled. * * @param values The progress values to update the UI with. diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index bc51a60..22e1476 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -49,7 +49,7 @@ public class Build { /** The manufacturer of the product/hardware. */ public static final String MANUFACTURER = getString("ro.product.manufacturer"); - /** The brand (e.g., carrier) the software is customized for, if any. */ + /** The consumer-visible brand with which the product/hardware will be associated, if any. */ public static final String BRAND = getString("ro.product.brand"); /** The end-user-visible name for the end product. */ diff --git a/core/java/android/os/FactoryTest.java b/core/java/android/os/FactoryTest.java index ec99697..7a252f9 100644 --- a/core/java/android/os/FactoryTest.java +++ b/core/java/android/os/FactoryTest.java @@ -25,6 +25,20 @@ package android.os; * {@hide} */ public final class FactoryTest { + public static final int FACTORY_TEST_OFF = 0; + public static final int FACTORY_TEST_LOW_LEVEL = 1; + public static final int FACTORY_TEST_HIGH_LEVEL = 2; + + /** + * Gets the current factory test mode. + * + * @return One of: {@link #FACTORY_TEST_OFF}, {@link #FACTORY_TEST_LOW_LEVEL}, + * or {@link #FACTORY_TEST_HIGH_LEVEL}. + */ + public static int getMode() { + return SystemProperties.getInt("ro.factorytest", FACTORY_TEST_OFF); + } + /** * When true, long-press on power should immediately cause the device to * shut down, without prompting the user. diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 5e0d489..86ef479 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -191,6 +191,18 @@ public final class PowerManager { public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020; /** + * Wake lock level: Put the screen in a low power state and allow the CPU to suspend + * if no other wake locks are held. + * <p> + * This is used by the dream manager to implement doze mode. It currently + * has no effect unless the power manager is in the dozing state. + * </p> + * + * {@hide} + */ + public static final int DOZE_WAKE_LOCK = 0x00000040; + + /** * Mask for the wake lock level component of a combined wake lock level and flags integer. * * @hide @@ -418,6 +430,7 @@ public final class PowerManager { case SCREEN_BRIGHT_WAKE_LOCK: case FULL_WAKE_LOCK: case PROXIMITY_SCREEN_OFF_WAKE_LOCK: + case DOZE_WAKE_LOCK: break; default: throw new IllegalArgumentException("Must specify a valid wake lock level."); diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java new file mode 100644 index 0000000..cb3d528 --- /dev/null +++ b/core/java/android/os/PowerManagerInternal.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 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.os; + +import android.view.WindowManagerPolicy; + +/** + * Power manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class PowerManagerInternal { + /** + * Used by the window manager to override the screen brightness based on the + * current foreground activity. + * + * This method must only be called by the window manager. + * + * @param brightness The overridden brightness, or -1 to disable the override. + */ + public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness); + + /** + * Used by the window manager to override the button brightness based on the + * current foreground activity. + * + * This method must only be called by the window manager. + * + * @param brightness The overridden brightness, or -1 to disable the override. + */ + public abstract void setButtonBrightnessOverrideFromWindowManager(int brightness); + + /** + * Used by the window manager to override the user activity timeout based on the + * current foreground activity. It can only be used to make the timeout shorter + * than usual, not longer. + * + * This method must only be called by the window manager. + * + * @param timeoutMillis The overridden timeout, or -1 to disable the override. + */ + public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis); + + // TODO: Remove this and retrieve as a local service instead. + public abstract void setPolicy(WindowManagerPolicy policy); +} diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 631edd6..057f516 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -892,19 +892,6 @@ public class Process { } /** - * Set the out-of-memory badness adjustment for a process. - * - * @param pid The process identifier to set. - * @param amt Adjustment value -- linux allows -16 to +15. - * - * @return Returns true if the underlying system supports this - * feature, else false. - * - * {@hide} - */ - public static final native boolean setOomAdj(int pid, int amt); - - /** * Adjust the swappiness level for a process. * * @param pid The process identifier to set. diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 7ddfa87..2ab5a91 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -33,6 +33,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.Log; import android.util.TypedValue; import android.util.Xml; import android.view.LayoutInflater; @@ -124,6 +125,8 @@ public abstract class PreferenceActivity extends ListActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback { + private static final String TAG = "PreferenceActivity"; + // Constants for state save/restore private static final String HEADERS_TAG = ":android:headers"; private static final String CUR_HEADER_TAG = ":android:cur_header"; @@ -521,9 +524,7 @@ public abstract class PreferenceActivity extends ListActivity implements int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0); int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0); - // Restore from headers only if they are supported which - // is in multi-pane mode. - if (savedInstanceState != null && !mSinglePane) { + if (savedInstanceState != null) { // We are restarting from a previous saved state; used that to // initialize, instead of starting fresh. ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG); diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index b16df28..0863368 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -18,6 +18,7 @@ package android.provider; import android.accounts.Account; import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentResolver; @@ -40,6 +41,7 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Pair; import android.view.View; +import android.widget.Toast; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -7981,7 +7983,7 @@ public final class ContactsContract { // Trigger with obtained rectangle Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, excludeMimes); - context.startActivity(intent); + startActivityWithErrorToast(context, intent); } /** @@ -8014,7 +8016,16 @@ public final class ContactsContract { String[] excludeMimes) { Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, excludeMimes); - context.startActivity(intent); + startActivityWithErrorToast(context, intent); + } + + private static void startActivityWithErrorToast(Context context, Intent intent) { + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available, + Toast.LENGTH_SHORT).show(); + } } } diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 86d3cf8..f0520b5 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -257,8 +257,6 @@ public final class DocumentsContract { * {@link #MIME_TYPE_DIR}. * * @see #COLUMN_FLAGS - * @see DocumentsContract#createDocument(ContentResolver, Uri, String, - * String) * @see DocumentsProvider#createDocument(String, String, String) */ public static final int FLAG_DIR_SUPPORTS_CREATE = 1 << 3; diff --git a/core/java/android/service/dreams/DozeHardware.java b/core/java/android/service/dreams/DozeHardware.java new file mode 100644 index 0000000..b5e7f43 --- /dev/null +++ b/core/java/android/service/dreams/DozeHardware.java @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2014 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.service.dreams; + +import android.os.RemoteException; +import android.util.Log; + +/** + * Provides access to low-level hardware features that a dream may use to provide + * a richer user experience while dozing. + * <p> + * This class contains functions that should be called by the dream to configure + * hardware before starting to doze and allowing the application processor to suspend. + * For example, the dream may provide the hardware with enough information to render + * some content on its own without any further assistance from the application processor. + * </p><p> + * This object is obtained by calling {@link DreamService#getDozeHardware()}. + * </p> + * + * @hide experimental + */ +public final class DozeHardware { + private static final String TAG = "DozeHardware"; + + public static final String MSG_ENABLE_MCU = "enable_mcu"; + + public static final byte[] VALUE_ON = "on".getBytes(); + public static final byte[] VALUE_OFF = "off".getBytes(); + + private final IDozeHardware mHardware; + + DozeHardware(IDozeHardware hardware) { + mHardware = hardware; + } + + /** + * Sets whether to enable the microcontroller. + * + * @param enable If true, enables the MCU otherwise disables it. + */ + public void setEnableMcu(boolean enable) { + sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF); + } + + /** + * Sends a message to the doze hardware module. + * + * @param msg The name of the message to send. + * @param arg An optional argument data blob, may be null. + * @return A result data blob, may be null. + */ + public byte[] sendMessage(String msg, byte[] arg) { + if (msg == null) { + throw new IllegalArgumentException("msg must not be null"); + } + + try { + return mHardware.sendMessage(msg, arg); + } catch (RemoteException ex) { + Log.e(TAG, "Failed to send message to doze hardware module.", ex); + return null; + } + } +} diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java new file mode 100644 index 0000000..9f7ddba --- /dev/null +++ b/core/java/android/service/dreams/DreamManagerInternal.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 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.service.dreams; + +/** + * Dream manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class DreamManagerInternal { + /** + * Called by the power manager to start a dream. + */ + public abstract void startDream(boolean doze); + + /** + * Called by the power manager to stop a dream. + */ + public abstract void stopDream(); + + /** + * Called by the power manager to determine whether a dream is running. + */ + public abstract boolean isDreaming(); +} diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index f6b6c89..7647c22 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -20,12 +20,14 @@ import java.io.PrintWriter; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.app.AlarmManager; import android.app.Service; import android.content.Intent; import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; import android.os.Handler; import android.os.IBinder; +import android.os.RemoteException; import android.os.ServiceManager; import android.util.Slog; import android.view.ActionMode; @@ -42,6 +44,8 @@ import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityEvent; import com.android.internal.policy.PolicyManager; +import com.android.internal.util.DumpUtils; +import com.android.internal.util.DumpUtils.Dump; /** * Extend this class to implement a custom dream (available to the user as a "Daydream"). @@ -145,19 +149,26 @@ public class DreamService extends Service implements Window.Callback { */ public static final String DREAM_META_DATA = "android.service.dream"; + private final IDreamManager mSandman; private final Handler mHandler = new Handler(); private IBinder mWindowToken; private Window mWindow; private WindowManager mWindowManager; - private IDreamManager mSandman; private boolean mInteractive = false; private boolean mLowProfile = true; private boolean mFullscreen = false; private boolean mScreenBright = true; private boolean mFinished; + private boolean mCanDoze; + private boolean mDozing; + private DozeHardware mDozeHardware; private boolean mDebug = false; + public DreamService() { + mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE)); + } + /** * @hide */ @@ -289,6 +300,10 @@ public class DreamService extends Service implements Window.Callback { public void onDetachedFromWindow() { } + @Override + public void onWindowDismissed() { + } + /** {@inheritDoc} */ @Override public void onPanelClosed(int featureId, Menu menu) { @@ -444,9 +459,11 @@ public class DreamService extends Service implements Window.Callback { * correct interactions with it (seeing when it is cleared etc). */ public void setLowProfile(boolean lowProfile) { - mLowProfile = lowProfile; - int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE; - applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag); + if (mLowProfile != lowProfile) { + mLowProfile = lowProfile; + int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE; + applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag); + } } /** @@ -467,9 +484,11 @@ public class DreamService extends Service implements Window.Callback { * will be cleared. */ public void setFullscreen(boolean fullscreen) { - mFullscreen = fullscreen; - int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN; - applyWindowFlags(mFullscreen ? flag : 0, flag); + if (mFullscreen != fullscreen) { + mFullscreen = fullscreen; + int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN; + applyWindowFlags(mFullscreen ? flag : 0, flag); + } } /** @@ -487,14 +506,16 @@ public class DreamService extends Service implements Window.Callback { * @param screenBright True to keep the screen bright while dreaming. */ public void setScreenBright(boolean screenBright) { - mScreenBright = screenBright; - int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; - applyWindowFlags(mScreenBright ? flag : 0, flag); + if (mScreenBright != screenBright) { + mScreenBright = screenBright; + int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; + applyWindowFlags(mScreenBright ? flag : 0, flag); + } } /** - * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false, - * allowing the screen to dim if necessary. + * Returns whether or not this dream keeps the screen bright while dreaming. + * Defaults to false, allowing the screen to dim if necessary. * * @see #setScreenBright(boolean) */ @@ -503,6 +524,119 @@ public class DreamService extends Service implements Window.Callback { } /** + * Returns true if this dream is allowed to doze. + * <p> + * The value returned by this method is only meaningful when the dream has started. + * </p> + * + * @return True if this dream can doze. + * @see #startDozing + * @hide experimental + */ + public boolean canDoze() { + return mCanDoze; + } + + /** + * Starts dozing, entering a deep dreamy sleep. + * <p> + * Dozing enables the system to conserve power while the user is not actively interacting + * with the device. While dozing, the display will remain on in a low-power state + * and will continue to show its previous contents but the application processor and + * other system components will be allowed to suspend when possible. + * </p><p> + * While the application processor is suspended, the dream may stop executing code + * for long periods of time. Prior to being suspended, the dream may schedule periodic + * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}. + * The dream may also keep the CPU awake by acquiring a + * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary. + * Note that since the purpose of doze mode is to conserve power (especially when + * running on battery), the dream should not wake the CPU very often or keep it + * awake for very long. + * </p><p> + * It is a good idea to call this method some time after the dream's entry animation + * has completed and the dream is ready to doze. It is important to completely + * finish all of the work needed before dozing since the application processor may + * be suspended at any moment once this method is called unless other wake locks + * are being held. + * </p><p> + * Call {@link #stopDozing} or {@link #finish} to stop dozing. + * </p> + * + * @see #stopDozing + * @hide experimental + */ + public void startDozing() { + if (mCanDoze && !mDozing) { + mDozing = true; + try { + mSandman.startDozing(mWindowToken); + } catch (RemoteException ex) { + // system server died + } + } + } + + /** + * Stops dozing, returns to active dreaming. + * <p> + * This method reverses the effect of {@link #startDozing}. From this moment onward, + * the application processor will be kept awake as long as the dream is running + * or until the dream starts dozing again. + * </p> + * + * @see #startDozing + * @hide experimental + */ + public void stopDozing() { + if (mDozing) { + mDozing = false; + try { + mSandman.stopDozing(mWindowToken); + } catch (RemoteException ex) { + // system server died + } + } + } + + /** + * Returns true if the dream will allow the system to enter a low-power state while + * it is running without actually turning off the screen. Defaults to false, + * keeping the application processor awake while the dream is running. + * + * @return True if the dream is dozing. + * + * @see #setDozing(boolean) + * @hide experimental + */ + public boolean isDozing() { + return mDozing; + } + + /** + * Gets an object that may be used to access low-level hardware features that a + * dream may use to provide a richer user experience while dozing. + * + * @return An instance of {@link DozeHardware} or null if this device does not offer + * hardware support for dozing. + * + * @hide experimental + */ + public DozeHardware getDozeHardware() { + if (mCanDoze && mDozeHardware == null) { + try { + IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken); + if (hardware != null) { + mDozeHardware = new DozeHardware(hardware); + } + } catch (RemoteException ex) { + // system server died + } + } + return mDozeHardware; + } + + /** * Called when this Dream is constructed. */ @Override @@ -536,7 +670,11 @@ public class DreamService extends Service implements Window.Callback { } /** - * Stops the dream, detaches from the window, and wakes up. + * Stops the dream and detaches from the window. + * <p> + * When the dream ends, the system will be allowed to go to sleep fully unless there + * is a reason for it to be awake such as recent user activity or wake locks being held. + * </p> */ public final void finish() { if (mDebug) Slog.v(TAG, "finish()"); @@ -557,10 +695,6 @@ public class DreamService extends Service implements Window.Callback { // end public api - private void loadSandman() { - mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE)); - } - /** * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed. * @@ -572,23 +706,16 @@ public class DreamService extends Service implements Window.Callback { return; } - try { - onDreamingStopped(); - } catch (Throwable t) { - Slog.w(TAG, "Crashed in onDreamingStopped()", t); - // we were going to stop anyway - } + if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()"); + onDreamingStopped(); if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager"); - try { - // force our window to be removed synchronously - mWindowManager.removeViewImmediate(mWindow.getDecorView()); - // the following will print a log message if it finds any other leaked windows - WindowManagerGlobal.getInstance().closeAll(mWindowToken, - this.getClass().getName(), "Dream"); - } catch (Throwable t) { - Slog.w(TAG, "Crashed removing window view", t); - } + + // force our window to be removed synchronously + mWindowManager.removeViewImmediate(mWindow.getDecorView()); + // the following will print a log message if it finds any other leaked windows + WindowManagerGlobal.getInstance().closeAll(mWindowToken, + this.getClass().getName(), "Dream"); mWindow = null; mWindowToken = null; @@ -601,23 +728,30 @@ public class DreamService extends Service implements Window.Callback { * * @param windowToken A window token that will allow a window to be created in the correct layer. */ - private final void attach(IBinder windowToken) { + private final void attach(IBinder windowToken, boolean canDoze) { if (mWindowToken != null) { Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken); return; } + if (mFinished) { + Slog.w(TAG, "attach() called after dream already finished"); + try { + mSandman.finishSelf(windowToken); + } catch (RemoteException ex) { + // system server died + } + return; + } if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId()); - if (mSandman == null) { - loadSandman(); - } mWindowToken = windowToken; mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); mWindow.requestFeature(Window.FEATURE_NO_TITLE); mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000)); mWindow.setFormat(PixelFormat.OPAQUE); + mCanDoze = canDoze; if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s", windowToken, WindowManager.LayoutParams.TYPE_DREAM)); @@ -642,40 +776,25 @@ public class DreamService extends Service implements Window.Callback { mWindowManager = mWindow.getWindowManager(); if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId()); - try { - applySystemUiVisibilityFlags( - (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0), - View.SYSTEM_UI_FLAG_LOW_PROFILE); - getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes()); - } catch (Throwable t) { - Slog.w(TAG, "Crashed adding window view", t); - safelyFinish(); - return; - } + applySystemUiVisibilityFlags( + (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0), + View.SYSTEM_UI_FLAG_LOW_PROFILE); + getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes()); // start it up mHandler.post(new Runnable() { @Override public void run() { - try { - onDreamingStarted(); - } catch (Throwable t) { - Slog.w(TAG, "Crashed in onDreamingStarted()", t); - safelyFinish(); - } + if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()"); + onDreamingStarted(); } }); } private void safelyFinish() { if (mDebug) Slog.v(TAG, "safelyFinish()"); - try { - finish(); - } catch (Throwable t) { - Slog.w(TAG, "Crashed in safelyFinish()", t); - finishInternal(); - return; - } + + finish(); if (!mFinished) { Slog.w(TAG, "Bad dream, did not call super.finish()"); @@ -685,19 +804,21 @@ public class DreamService extends Service implements Window.Callback { private void finishInternal() { if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished); - if (mFinished) return; - try { + + if (!mFinished) { mFinished = true; - if (mSandman != null) { - mSandman.finishSelf(mWindowToken); + if (mWindowToken == null) { + Slog.w(TAG, "Finish was called before the dream was attached."); } else { - Slog.w(TAG, "No dream manager found"); + try { + mSandman.finishSelf(mWindowToken); + } catch (RemoteException ex) { + // system server died + } } - stopSelf(); // if launched via any other means - } catch (Throwable t) { - Slog.w(TAG, "Crashed in finishInternal()", t); + stopSelf(); // if launched via any other means } } @@ -732,32 +853,39 @@ public class DreamService extends Service implements Window.Callback { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - super.dump(fd, pw, args); - - pw.print(TAG + ": "); - if (mWindowToken == null) { - pw.println("stopped"); - } else { - pw.println("running (token=" + mWindowToken + ")"); - } - pw.println(" window: " + mWindow); - pw.print(" flags:"); - if (isInteractive()) pw.print(" interactive"); - if (isLowProfile()) pw.print(" lowprofile"); - if (isFullscreen()) pw.print(" fullscreen"); - if (isScreenBright()) pw.print(" bright"); - pw.println(); + DumpUtils.dumpAsync(mHandler, new Dump() { + @Override + public void dump(PrintWriter pw) { + pw.print(TAG + ": "); + if (mWindowToken == null) { + pw.println("stopped"); + } else { + pw.println("running (token=" + mWindowToken + ")"); + } + pw.println(" window: " + mWindow); + pw.print(" flags:"); + if (isInteractive()) pw.print(" interactive"); + if (isLowProfile()) pw.print(" lowprofile"); + if (isFullscreen()) pw.print(" fullscreen"); + if (isScreenBright()) pw.print(" bright"); + if (isDozing()) pw.print(" dozing"); + pw.println(); + } + }, pw, 1000); } - private class DreamServiceWrapper extends IDreamService.Stub { - public void attach(final IBinder windowToken) { + private final class DreamServiceWrapper extends IDreamService.Stub { + @Override + public void attach(final IBinder windowToken, final boolean canDoze) { mHandler.post(new Runnable() { @Override public void run() { - DreamService.this.attach(windowToken); + DreamService.this.attach(windowToken, canDoze); } }); } + + @Override public void detach() { mHandler.post(new Runnable() { @Override diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/core/java/android/service/dreams/IDozeHardware.aidl new file mode 100644 index 0000000..f5a657b --- /dev/null +++ b/core/java/android/service/dreams/IDozeHardware.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 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.service.dreams; + +/** + * @hide + */ +interface IDozeHardware { + byte[] sendMessage(String msg, in byte[] arg); +} diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl index 1c1b390..2718e31 100644 --- a/core/java/android/service/dreams/IDreamManager.aidl +++ b/core/java/android/service/dreams/IDreamManager.aidl @@ -16,10 +16,11 @@ package android.service.dreams; +import android.content.ComponentName; import android.os.Bundle; import android.os.ParcelFileDescriptor; -import android.content.ComponentName; import android.os.IBinder; +import android.service.dreams.IDozeHardware; /** @hide */ interface IDreamManager { @@ -31,4 +32,7 @@ interface IDreamManager { void testDream(in ComponentName componentName); boolean isDreaming(); void finishSelf(in IBinder token); + void startDozing(in IBinder token); + void stopDozing(in IBinder token); + IDozeHardware getDozeHardware(in IBinder token); }
\ No newline at end of file diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl index 99dc0b7..bd58f1d 100644 --- a/core/java/android/service/dreams/IDreamService.aidl +++ b/core/java/android/service/dreams/IDreamService.aidl @@ -20,6 +20,6 @@ package android.service.dreams; * @hide */ oneway interface IDreamService { - void attach(IBinder windowToken); + void attach(IBinder windowToken, boolean canDoze); void detach(); } diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 2e0e59b..cf862b8 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -112,6 +112,7 @@ public abstract class NotificationListenerService extends Service { * {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}. */ public final void cancelNotification(String pkg, String tag, int id) { + if (!isBound()) return; try { getNotificationInterface().cancelNotificationFromListener(mWrapper, pkg, tag, id); } catch (android.os.RemoteException ex) { @@ -131,6 +132,7 @@ public abstract class NotificationListenerService extends Service { * {@see #cancelNotification(String, String, int)} */ public final void cancelAllNotifications() { + if (!isBound()) return; try { getNotificationInterface().cancelAllNotificationsFromListener(mWrapper); } catch (android.os.RemoteException ex) { @@ -145,6 +147,7 @@ public abstract class NotificationListenerService extends Service { * @return An array of active notifications. */ public StatusBarNotification[] getActiveNotifications() { + if (!isBound()) return null; try { return getNotificationInterface().getActiveNotificationsFromListener(mWrapper); } catch (android.os.RemoteException ex) { @@ -161,6 +164,14 @@ public abstract class NotificationListenerService extends Service { return mWrapper; } + private boolean isBound() { + if (mWrapper == null) { + Log.w(TAG, "Notification listener service not yet bound."); + return false; + } + return true; + } + private class INotificationListenerWrapper extends INotificationListener.Stub { @Override public void onNotificationPosted(StatusBarNotification sbn) { diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index 5ef86b1..f34e746 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -512,7 +512,7 @@ public class Time { * <pre> * Time time = new Time(); * time.set(4, 10, 2007); // set the date to Nov 4, 2007, 12am - * time.normalize(); // this sets isDst = 1 + * time.normalize(false); // this sets isDst = 1 * time.monthDay += 1; // changes the date to Nov 5, 2007, 12am * millis = time.toMillis(false); // millis is Nov 4, 2007, 11pm * millis = time.toMillis(true); // millis is Nov 5, 2007, 12am diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java index d6e116f..dab853a 100644 --- a/core/java/android/util/LongSparseArray.java +++ b/core/java/android/util/LongSparseArray.java @@ -44,7 +44,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class LongSparseArray<E> implements Cloneable { private static final Object DELETED = new Object(); diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java index 87d868b..6654899 100644 --- a/core/java/android/util/LongSparseLongArray.java +++ b/core/java/android/util/LongSparseLongArray.java @@ -39,7 +39,7 @@ import java.util.Arrays; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> * * @hide */ diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 6e168a8..46d9d45 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -44,7 +44,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class SparseArray<E> implements Cloneable { private static final Object DELETED = new Object(); diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java index 68487e3..905dcb0 100644 --- a/core/java/android/util/SparseBooleanArray.java +++ b/core/java/android/util/SparseBooleanArray.java @@ -38,7 +38,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class SparseBooleanArray implements Cloneable { /** diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index 0835cb0..4f5ca07 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -37,7 +37,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class SparseIntArray implements Cloneable { private int[] mKeys; diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java index 62c1c0d..39fc8a3 100644 --- a/core/java/android/util/SparseLongArray.java +++ b/core/java/android/util/SparseLongArray.java @@ -37,7 +37,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class SparseLongArray implements Cloneable { private int[] mKeys; diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java index ed45298..931fb81 100644 --- a/core/java/android/util/TypedValue.java +++ b/core/java/android/util/TypedValue.java @@ -290,18 +290,14 @@ public class TypedValue { return -1; } + /** + * @hide Was accidentally exposed in API level 1 for debugging purposes. + * Kept for compatibility just in case although the debugging code has been removed. + */ + @Deprecated public static float complexToDimensionNoisy(int data, DisplayMetrics metrics) { - float res = complexToDimension(data, metrics); - System.out.println( - "Dimension (0x" + ((data>>TypedValue.COMPLEX_MANTISSA_SHIFT) - & TypedValue.COMPLEX_MANTISSA_MASK) - + "*" + (RADIX_MULTS[(data>>TypedValue.COMPLEX_RADIX_SHIFT) - & TypedValue.COMPLEX_RADIX_MASK] / MANTISSA_MULT) - + ")" + DIMENSION_UNIT_STRS[(data>>COMPLEX_UNIT_SHIFT) - & COMPLEX_UNIT_MASK] - + " = " + res); - return res; + return complexToDimension(data, metrics); } /** diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 62afa60..eea5884 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -79,9 +79,6 @@ public class SurfaceControl { private final String mName; long mNativeObject; // package visibility only for Surface.java access - private static final boolean HEADLESS = "1".equals( - SystemProperties.get("ro.config.headless", "0")); - /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */ /** @@ -106,18 +103,18 @@ public class SurfaceControl { * surfaces are pre-multiplied, which means that each color component is * already multiplied by its alpha value. In this case the blending * equation used is: - * - * DEST = SRC + DEST * (1-SRC_ALPHA) - * + * <p> + * <code>DEST = SRC + DEST * (1-SRC_ALPHA)</code> + * <p> * By contrast, non pre-multiplied surfaces use the following equation: - * - * DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA) - * + * <p> + * <code>DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA)</code> + * <p> * pre-multiplied surfaces must always be used if transparent pixels are * composited on top of each-other into the surface. A pre-multiplied * surface can never lower the value of the alpha component of a given * pixel. - * + * <p> * In some rare situations, a non pre-multiplied surface is preferable. * */ @@ -128,7 +125,17 @@ public class SurfaceControl { * even if its pixel format is set to translucent. This can be useful if an * application needs full RGBA 8888 support for instance but will * still draw every pixel opaque. - * + * <p> + * This flag is ignored if setAlpha() is used to make the surface non-opaque. + * Combined effects are (assuming a buffer format with an alpha channel): + * <ul> + * <li>OPAQUE + alpha(1.0) == opaque composition + * <li>OPAQUE + alpha(0.x) == blended composition + * <li>!OPAQUE + alpha(1.0) == blended composition + * <li>!OPAQUE + alpha(0.x) == blended composition + * </ul> + * If the underlying buffer lacks an alpha channel, the OPAQUE flag is effectively + * set automatically. */ public static final int OPAQUE = 0x00000400; @@ -169,9 +176,16 @@ public class SurfaceControl { /** * Surface flag: Hide the surface. * Equivalent to calling hide(). + * Updates the value set during Surface creation (see {@link #HIDDEN}). */ public static final int SURFACE_HIDDEN = 0x01; + /** + * Surface flag: composite without blending when possible. + * Updates the value set during Surface creation (see {@link #OPAQUE}). + */ + public static final int SURFACE_OPAQUE = 0x02; + /* built-in physical display ids (keep in sync with ISurfaceComposer.h) * these are different from the logical display ids used elsewhere in the framework */ @@ -192,14 +206,14 @@ public class SurfaceControl { /** * Create a surface with a name. - * + * <p> * The surface creation flags specify what kind of surface to create and * certain options such as whether the surface can be assumed to be opaque * and whether it should be initially hidden. Surfaces should always be * created with the {@link #HIDDEN} flag set to ensure that they are not * made visible prematurely before all of the surface's properties have been * configured. - * + * <p> * Good practice is to first create the surface with the {@link #HIDDEN} flag * specified, open a transaction, set the surface layer, layer stack, alpha, * and position, call {@link #show} if appropriate, and close the transaction. @@ -232,8 +246,6 @@ public class SurfaceControl { new Throwable()); } - checkHeadless(); - mName = name; mNativeObject = nativeCreate(session, name, w, h, format, flags); if (mNativeObject == 0) { @@ -344,6 +356,10 @@ public class SurfaceControl { nativeSetTransparentRegionHint(mNativeObject, region); } + /** + * Sets an alpha value for the entire Surface. This value is combined with the + * per-pixel alpha. It may be used with opaque Surfaces. + */ public void setAlpha(float alpha) { checkNotReleased(); nativeSetAlpha(mNativeObject, alpha); @@ -354,6 +370,13 @@ public class SurfaceControl { nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy); } + /** + * Sets and clears flags, such as {@link #SURFACE_HIDDEN}. The new value will be: + * <p> + * <code>newFlags = (oldFlags & ~mask) | (flags & mask)</code> + * <p> + * Note this does not take the same set of flags as the constructor. + */ public void setFlags(int flags, int mask) { checkNotReleased(); nativeSetFlags(mNativeObject, flags, mask); @@ -374,6 +397,19 @@ public class SurfaceControl { nativeSetLayerStack(mNativeObject, layerStack); } + /** + * Sets the opacity of the surface. Setting the flag is equivalent to creating the + * Surface with the {@link #OPAQUE} flag. + */ + public void setOpaque(boolean isOpaque) { + checkNotReleased(); + if (isOpaque) { + nativeSetFlags(mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE); + } else { + nativeSetFlags(mNativeObject, 0, SURFACE_OPAQUE); + } + } + /* * set display parameters. * needs to be inside open/closeTransaction block @@ -619,10 +655,4 @@ public class SurfaceControl { } nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers); } - - private static void checkHeadless() { - if (HEADLESS) { - throw new UnsupportedOperationException("Device is headless"); - } - } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 9414237..5763e72 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -463,13 +463,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public ViewGroup(Context context, AttributeSet attrs) { super(context, attrs); initViewGroup(); - initFromAttributes(context, attrs); + initFromAttributes(context, attrs, 0); } public ViewGroup(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initViewGroup(); - initFromAttributes(context, attrs); + initFromAttributes(context, attrs, defStyle); } private boolean debugDraw() { @@ -499,9 +499,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE; } - private void initFromAttributes(Context context, AttributeSet attrs) { - TypedArray a = context.obtainStyledAttributes(attrs, - R.styleable.ViewGroup); + private void initFromAttributes(Context context, AttributeSet attrs, int defStyle) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyle, 0); final int N = a.getIndexCount(); for (int i = 0; i < N; i++) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index bc0d7e3..d779628 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -232,8 +232,6 @@ public final class ViewRootImpl implements ViewParent, InputStage mFirstInputStage; InputStage mFirstPostImeInputStage; - boolean mFlipControllerFallbackKeys; - boolean mWindowAttributesChanged = false; int mWindowAttributesChangesFlag = 0; @@ -370,8 +368,6 @@ public final class ViewRootImpl implements ViewParent, mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context); mChoreographer = Choreographer.getInstance(); - mFlipControllerFallbackKeys = - context.getResources().getBoolean(R.bool.flip_controller_fallback_keys); PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mAttachInfo.mScreenOn = powerManager.isScreenOn(); @@ -2912,11 +2908,8 @@ public final class ViewRootImpl implements ViewParent, mView.dispatchConfigurationChanged(config); } } - - mFlipControllerFallbackKeys = - mContext.getResources().getBoolean(R.bool.flip_controller_fallback_keys); } - + /** * Return true if child is an ancestor of parent, (or equal to the parent). */ @@ -3985,7 +3978,6 @@ public final class ViewRootImpl implements ViewParent, private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler(); private final SyntheticTouchNavigationHandler mTouchNavigation = new SyntheticTouchNavigationHandler(); - private final SyntheticKeyHandler mKeys = new SyntheticKeyHandler(); public SyntheticInputStage() { super(null); @@ -4008,12 +4000,7 @@ public final class ViewRootImpl implements ViewParent, mTouchNavigation.process(event); return FINISH_HANDLED; } - } else if (q.mEvent instanceof KeyEvent) { - if (mKeys.process((KeyEvent) q.mEvent)) { - return FINISH_HANDLED; - } } - return FORWARD; } @@ -4843,63 +4830,6 @@ public final class ViewRootImpl implements ViewParent, }; } - final class SyntheticKeyHandler { - - public boolean process(KeyEvent event) { - // In some locales (like Japan) controllers use B for confirm and A for back, rather - // than vice versa, so we need to special case this here since the input system itself - // is not locale-aware. - int keyCode; - switch(event.getKeyCode()) { - case KeyEvent.KEYCODE_BUTTON_A: - case KeyEvent.KEYCODE_BUTTON_C: - case KeyEvent.KEYCODE_BUTTON_X: - case KeyEvent.KEYCODE_BUTTON_Z: - keyCode = mFlipControllerFallbackKeys ? - KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_DPAD_CENTER; - break; - case KeyEvent.KEYCODE_BUTTON_B: - case KeyEvent.KEYCODE_BUTTON_Y: - keyCode = mFlipControllerFallbackKeys ? - KeyEvent.KEYCODE_DPAD_CENTER : KeyEvent.KEYCODE_BACK; - break; - case KeyEvent.KEYCODE_BUTTON_THUMBL: - case KeyEvent.KEYCODE_BUTTON_THUMBR: - case KeyEvent.KEYCODE_BUTTON_START: - case KeyEvent.KEYCODE_BUTTON_1: - case KeyEvent.KEYCODE_BUTTON_2: - case KeyEvent.KEYCODE_BUTTON_3: - case KeyEvent.KEYCODE_BUTTON_4: - case KeyEvent.KEYCODE_BUTTON_5: - case KeyEvent.KEYCODE_BUTTON_6: - case KeyEvent.KEYCODE_BUTTON_7: - case KeyEvent.KEYCODE_BUTTON_8: - case KeyEvent.KEYCODE_BUTTON_9: - case KeyEvent.KEYCODE_BUTTON_10: - case KeyEvent.KEYCODE_BUTTON_11: - case KeyEvent.KEYCODE_BUTTON_12: - case KeyEvent.KEYCODE_BUTTON_13: - case KeyEvent.KEYCODE_BUTTON_14: - case KeyEvent.KEYCODE_BUTTON_15: - case KeyEvent.KEYCODE_BUTTON_16: - keyCode = KeyEvent.KEYCODE_DPAD_CENTER; - break; - case KeyEvent.KEYCODE_BUTTON_SELECT: - case KeyEvent.KEYCODE_BUTTON_MODE: - keyCode = KeyEvent.KEYCODE_MENU; - default: - return false; - } - - enqueueInputEvent(new KeyEvent(event.getDownTime(), event.getEventTime(), - event.getAction(), keyCode, event.getRepeatCount(), event.getMetaState(), - event.getDeviceId(), event.getScanCode(), - event.getFlags() | KeyEvent.FLAG_FALLBACK, event.getSource())); - return true; - } - - } - /** * Returns true if the key is used for keyboard navigation. * @param keyEvent The key event. diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index f0e6677..52f9c0b 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -311,7 +311,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie lp.type = LayoutParams.TYPE_VOLUME_OVERLAY; lp.width = LayoutParams.WRAP_CONTENT; lp.height = LayoutParams.WRAP_CONTENT; - lp.privateFlags |= LayoutParams.PRIVATE_FLAG_FORCE_SHOW_NAV_BAR; window.setAttributes(lp); window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index b3a0699..c450f3c 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -91,10 +91,15 @@ public abstract class Window { public static final int FEATURE_ACTION_MODE_OVERLAY = 10; /** + * Flag for requesting a decoration-free window that is dismissed by swiping from the left. + */ + public static final int FEATURE_SWIPE_TO_DISMISS = 11; + + /** * Max value used as a feature ID * @hide */ - public static final int FEATURE_MAX = FEATURE_ACTION_MODE_OVERLAY; + public static final int FEATURE_MAX = FEATURE_SWIPE_TO_DISMISS; /** Flag for setting the progress bar's visibility to VISIBLE */ public static final int PROGRESS_VISIBILITY_ON = -1; @@ -385,6 +390,12 @@ public abstract class Window { * @param mode The mode that was just finished. */ public void onActionModeFinished(ActionMode mode); + + /** + * Called when a window is dismissed. This informs the callback that the + * window is gone, and it should finish itself. + */ + public void onWindowDismissed(); } public Window(Context context) { diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 0ce4da5..53a4c0d0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1063,13 +1063,6 @@ public interface WindowManager extends ViewManager { public static final int PRIVATE_FLAG_SHOW_FOR_ALL_USERS = 0x00000010; /** - * Special flag for the volume overlay: force the window manager out of "hide nav bar" - * mode while the window is on screen. - * - * {@hide} */ - public static final int PRIVATE_FLAG_FORCE_SHOW_NAV_BAR = 0x00000020; - - /** * Never animate position changes of the window. * * {@hide} */ diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java new file mode 100644 index 0000000..a1bd4bd --- /dev/null +++ b/core/java/android/view/WindowManagerInternal.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 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.view; + +import android.hardware.display.DisplayManagerInternal; + +/** + * Window manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class WindowManagerInternal { + /** + * Request that the window manager call + * {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager} + * within a surface transaction at a later time. + */ + public abstract void requestTraversalFromDisplayManager(); +}
\ No newline at end of file diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index c5a1b86..74dda77 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -115,20 +115,6 @@ public interface WindowManagerPolicy { public final static int ACTION_PASS_TO_USER = 0x00000001; /** - * This key event should wake the device. - * To be returned from {@link #interceptKeyBeforeQueueing}. - * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}. - */ - public final static int ACTION_WAKE_UP = 0x00000002; - - /** - * This key event should put the device to sleep (and engage keyguard if necessary) - * To be returned from {@link #interceptKeyBeforeQueueing}. - * Do not return this and {@link #ACTION_WAKE_UP} or {@link #ACTION_PASS_TO_USER}. - */ - public final static int ACTION_GO_TO_SLEEP = 0x00000004; - - /** * Interface to the Window Manager state associated with a particular * window. You can hold on to an instance of this interface from the call * to prepareAddWindow() until removeWindow(). @@ -751,8 +737,7 @@ public interface WindowManagerPolicy { * @param policyFlags The policy flags associated with the key. * @param isScreenOn True if the screen is already on * - * @return The bitwise or of the {@link #ACTION_PASS_TO_USER}, - * {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags. + * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}. */ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn); @@ -765,10 +750,9 @@ public interface WindowManagerPolicy { * because it's the most fragile. * @param policyFlags The policy flags associated with the motion. * - * @return The bitwise or of the {@link #ACTION_PASS_TO_USER}, - * {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags. + * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}. */ - public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags); + public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags); /** * Called from the input dispatcher thread before a key is dispatched to a window. diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 00f4adb..879e58f 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -177,7 +177,8 @@ public final class AccessibilityManager { userId = UserHandle.myUserId(); } IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE); - IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder); + IAccessibilityManager service = iBinder == null + ? null : IAccessibilityManager.Stub.asInterface(iBinder); sInstance = new AccessibilityManager(context, service, userId); } } @@ -197,10 +198,14 @@ public final class AccessibilityManager { mHandler = new MyHandler(context.getMainLooper()); mService = service; mUserId = userId; - + if (mService == null) { + mIsEnabled = false; + } try { - final int stateFlags = mService.addClient(mClient, userId); - setState(stateFlags); + if (mService != null) { + final int stateFlags = mService.addClient(mClient, userId); + setState(stateFlags); + } } catch (RemoteException re) { Log.e(LOG_TAG, "AccessibilityManagerService is dead", re); } @@ -322,14 +327,16 @@ public final class AccessibilityManager { public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() { List<AccessibilityServiceInfo> services = null; try { - services = mService.getInstalledAccessibilityServiceList(mUserId); - if (DEBUG) { - Log.i(LOG_TAG, "Installed AccessibilityServices " + services); + if (mService != null) { + services = mService.getInstalledAccessibilityServiceList(mUserId); + if (DEBUG) { + Log.i(LOG_TAG, "Installed AccessibilityServices " + services); + } } } catch (RemoteException re) { Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re); } - return Collections.unmodifiableList(services); + return services != null ? Collections.unmodifiableList(services) : Collections.EMPTY_LIST; } /** @@ -349,14 +356,16 @@ public final class AccessibilityManager { int feedbackTypeFlags) { List<AccessibilityServiceInfo> services = null; try { - services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags, mUserId); - if (DEBUG) { - Log.i(LOG_TAG, "Installed AccessibilityServices " + services); + if (mService != null) { + services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags, mUserId); + if (DEBUG) { + Log.i(LOG_TAG, "Installed AccessibilityServices " + services); + } } } catch (RemoteException re) { Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re); } - return Collections.unmodifiableList(services); + return services != null ? Collections.unmodifiableList(services) : Collections.EMPTY_LIST; } /** @@ -466,6 +475,9 @@ public final class AccessibilityManager { */ public int addAccessibilityInteractionConnection(IWindow windowToken, IAccessibilityInteractionConnection connection) { + if (mService == null) { + return View.NO_ID; + } try { return mService.addAccessibilityInteractionConnection(windowToken, connection, mUserId); } catch (RemoteException re) { @@ -482,7 +494,9 @@ public final class AccessibilityManager { */ public void removeAccessibilityInteractionConnection(IWindow windowToken) { try { - mService.removeAccessibilityInteractionConnection(windowToken); + if (mService != null) { + mService.removeAccessibilityInteractionConnection(windowToken); + } } catch (RemoteException re) { Log.e(LOG_TAG, "Error while removing an accessibility interaction connection. ", re); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 5bc39f1..d53bb74 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -686,6 +686,15 @@ public class WebView extends AbsoluteLayout } /** + * Used only by internal tests to free up memory. + * + * @hide + */ + public static void freeMemoryForTests() { + getFactory().getStatics().freeMemoryForTests(); + } + + /** * Informs WebView of the network state. This is used to set * the JavaScript property window.navigator.isOnline and * generates the online/offline event as specified in HTML5, sec. 5.7.7 diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java index 9d9d882..e391aaf 100644 --- a/core/java/android/webkit/WebViewFactoryProvider.java +++ b/core/java/android/webkit/WebViewFactoryProvider.java @@ -50,6 +50,11 @@ public interface WebViewFactoryProvider { String getDefaultUserAgent(Context context); /** + * Used for tests only. + */ + void freeMemoryForTests(); + + /** * Implements the API method: * {@link android.webkit.WebView#setWebContentsDebuggingEnabled(boolean) } */ diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 092f474..1899a1d 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -723,7 +723,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * * @param view The view whose scroll state is being reported * - * @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE}, + * @param scrollState The current scroll state. One of * {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}. */ public void onScrollStateChanged(AbsListView view, int scrollState); diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 0957ab4..e90b460 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -1210,35 +1210,38 @@ public class CalendarView extends FrameLayout { child = (WeekView) view.getChildAt(offset); } - // Find out which month we're moving into - int month; - if (mIsScrollingUp) { - month = child.getMonthOfFirstWeekDay(); - } else { - month = child.getMonthOfLastWeekDay(); - } - - // And how it relates to our current highlighted month - int monthDiff; - if (mCurrentMonthDisplayed == 11 && month == 0) { - monthDiff = 1; - } else if (mCurrentMonthDisplayed == 0 && month == 11) { - monthDiff = -1; - } else { - monthDiff = month - mCurrentMonthDisplayed; - } - - // Only switch months if we're scrolling away from the currently - // selected month - if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) { - Calendar firstDay = child.getFirstDay(); + if (child != null) { + // Find out which month we're moving into + int month; if (mIsScrollingUp) { - firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK); + month = child.getMonthOfFirstWeekDay(); } else { - firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK); + month = child.getMonthOfLastWeekDay(); + } + + // And how it relates to our current highlighted month + int monthDiff; + if (mCurrentMonthDisplayed == 11 && month == 0) { + monthDiff = 1; + } else if (mCurrentMonthDisplayed == 0 && month == 11) { + monthDiff = -1; + } else { + monthDiff = month - mCurrentMonthDisplayed; + } + + // Only switch months if we're scrolling away from the currently + // selected month + if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) { + Calendar firstDay = child.getFirstDay(); + if (mIsScrollingUp) { + firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK); + } else { + firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK); + } + setMonthDisplayed(firstDay); } - setMonthDisplayed(firstDay); } + mPreviousScrollPosition = currScroll; mPreviousScrollState = mCurrentScrollState; } diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 7daf798..f05179b 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -563,7 +563,7 @@ public class ImageView extends View { } /** Return the view's optional matrix. This is applied to the - view's drawable when it is drawn. If there is not matrix, + view's drawable when it is drawn. If there is no matrix, this method will return an identity matrix. Do not change this matrix in place but make a copy. If you want a different matrix applied to the drawable, diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index c0fde2e..9c6a2e3 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -427,12 +427,12 @@ public class NumberPicker extends LinearLayout { * Flag whether to ignore move events - we ignore such when we show in IME * to prevent the content from scrolling. */ - private boolean mIngonreMoveEvents; + private boolean mIgnoreMoveEvents; /** - * Flag whether to show soft input on tap. + * Flag whether to perform a click on tap. */ - private boolean mShowSoftInputOnTap; + private boolean mPerformClickOnTap; /** * The top of the top selection divider. @@ -808,8 +808,8 @@ public class NumberPicker extends LinearLayout { mInputText.setVisibility(View.INVISIBLE); mLastDownOrMoveEventY = mLastDownEventY = event.getY(); mLastDownEventTime = event.getEventTime(); - mIngonreMoveEvents = false; - mShowSoftInputOnTap = false; + mIgnoreMoveEvents = false; + mPerformClickOnTap = false; // Handle pressed state before any state change. if (mLastDownEventY < mTopSelectionDividerTop) { if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { @@ -840,7 +840,7 @@ public class NumberPicker extends LinearLayout { postChangeCurrentByOneFromLongPress( true, ViewConfiguration.getLongPressTimeout()); } else { - mShowSoftInputOnTap = true; + mPerformClickOnTap = true; postBeginSoftInputOnLongPressCommand(); } return true; @@ -861,7 +861,7 @@ public class NumberPicker extends LinearLayout { int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_MOVE: { - if (mIngonreMoveEvents) { + if (mIgnoreMoveEvents) { break; } float currentMoveY = event.getY(); @@ -893,9 +893,9 @@ public class NumberPicker extends LinearLayout { int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY); long deltaTime = event.getEventTime() - mLastDownEventTime; if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) { - if (mShowSoftInputOnTap) { - mShowSoftInputOnTap = false; - showSoftInput(); + if (mPerformClickOnTap) { + mPerformClickOnTap = false; + performClick(); } else { int selectorIndexOffset = (eventY / mSelectorElementHeight) - SELECTOR_MIDDLE_ITEM_INDEX; @@ -1188,6 +1188,27 @@ public class NumberPicker extends LinearLayout { setValueInternal(value, false); } + @Override + public boolean performClick() { + if (!mHasSelectorWheel) { + return super.performClick(); + } else if (!super.performClick()) { + showSoftInput(); + } + return true; + } + + @Override + public boolean performLongClick() { + if (!mHasSelectorWheel) { + return super.performLongClick(); + } else if (!super.performLongClick()) { + showSoftInput(); + mIgnoreMoveEvents = true; + } + return true; + } + /** * Shows the soft input for its input text. */ @@ -2166,8 +2187,7 @@ public class NumberPicker extends LinearLayout { @Override public void run() { - showSoftInput(); - mIngonreMoveEvents = true; + performLongClick(); } } @@ -2295,7 +2315,14 @@ public class NumberPicker extends LinearLayout { } case AccessibilityNodeInfo.ACTION_CLICK: { if (NumberPicker.this.isEnabled()) { - showSoftInput(); + performClick(); + return true; + } + return false; + } + case AccessibilityNodeInfo.ACTION_LONG_CLICK: { + if (NumberPicker.this.isEnabled()) { + performLongClick(); return true; } return false; diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 5663959..be20d2d 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1330,7 +1330,7 @@ public class PopupWindow { /** * Updates the state of the popup window, if it is currently being displayed, - * from the currently set state. This include: + * from the currently set state. This includes: * {@link #setClippingEnabled(boolean)}, {@link #setFocusable(boolean)}, * {@link #setIgnoreCheekPress()}, {@link #setInputMethodMode(int)}, * {@link #setTouchable(boolean)}, and {@link #setAnimationStyle(int)}. diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 5392a96..6a369a6 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -308,6 +308,11 @@ public class ProgressBar extends View { mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl); a.recycle(); + + // If not explicitly specified this view is important for accessibility. + if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); + } } /** diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java index 62afd2e..bdaaa01 100644 --- a/core/java/android/widget/ShareActionProvider.java +++ b/core/java/android/widget/ShareActionProvider.java @@ -266,7 +266,7 @@ public class ShareActionProvider extends ActionProvider { * Intent shareIntent = new Intent(Intent.ACTION_SEND); * shareIntent.setType("image/*"); * Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg")); - * shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());</pre> + * shareIntent.putExtra(Intent.EXTRA_STREAM, uri));</pre> * * @param shareIntent The share intent. * diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 7a9809f..37121e2 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8667,6 +8667,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.onRtlPropertiesChanged(layoutDirection); mTextDir = getTextDirectionHeuristic(); + + if (mLayout != null) { + checkForRelayout(); + } } TextDirectionHeuristic getTextDirectionHeuristic() { |
